-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Redact CoercePointee target type #136796
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Redact CoercePointee target type #136796
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -85,6 +85,23 @@ 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_unsized = `{$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_dispatch_from_dyn = `{$ty}` cannot be coerced to an unsized type, to which `dyn` methods can be dispatched | ||
.note = `derive(CoercePointee)` demands that `dyn` methods can be dispatched when `{$ty}` can be coerced to an unsized type | ||
.help = `dyn` methods can be dispatched to the standard pointers such as `Arc`, `Rc`, `Box`, and other types with `derive(CoercePointee)` | ||
hir_analysis_coerce_pointee_cannot_unsize = `{$ty}` cannot be coerced to an unsized value | ||
.note = `derive(CoercePointee)` demands that `{$ty}` can be coerced to an unsized type | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar, this note is not exercised by any test? |
||
.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 | ||
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
use rustc_hir::LangItem; | ||
use rustc_hir::def_id::DefId; | ||
use rustc_middle::ty::fast_reject::SimplifiedType; | ||
use rustc_middle::ty::{ | ||
self, GenericParamDefKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, | ||
}; | ||
use rustc_span::{Span, sym}; | ||
use rustc_trait_selection::traits::FulfillmentError; | ||
use tracing::instrument; | ||
|
||
use crate::errors; | ||
|
||
#[instrument(level = "debug", skip(tcx), ret)] | ||
pub(super) fn extract_coerce_pointee_data<'tcx>( | ||
tcx: TyCtxt<'tcx>, | ||
adt_did: DefId, | ||
) -> Option<usize> { | ||
// It is decided that a query to cache these results is not necessary | ||
// for error reporting. | ||
// We can afford to recompute it on-demand. | ||
if tcx.lang_items().get(LangItem::CoercePointeeValidated).map_or(false, |did| { | ||
tcx.trait_impls_of(did).non_blanket_impls().contains_key(&SimplifiedType::Adt(adt_did)) | ||
}) { | ||
// Search for the `#[pointee]` | ||
enum Pointee { | ||
None, | ||
First(usize), | ||
Ambiguous, | ||
} | ||
let mut first_type = Pointee::None; | ||
for (idx, param) in tcx.generics_of(adt_did).own_params.iter().enumerate() { | ||
if let GenericParamDefKind::Type { .. } = param.kind { | ||
match first_type { | ||
Pointee::None => { | ||
first_type = Pointee::First(idx); | ||
} | ||
Pointee::First(_) => first_type = Pointee::Ambiguous, | ||
Pointee::Ambiguous => {} | ||
} | ||
} | ||
if tcx.has_attr(param.def_id, sym::pointee) { | ||
return Some(idx); | ||
} | ||
} | ||
if let Pointee::First(idx) = first_type { | ||
return Some(idx); | ||
} | ||
} | ||
None | ||
} | ||
|
||
fn contains_coerce_pointee_target_pointee<'tcx>(ty: Ty<'tcx>, target_pointee_ty: Ty<'tcx>) -> bool { | ||
struct Search<'tcx> { | ||
pointee: Ty<'tcx>, | ||
found: bool, | ||
} | ||
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> { | ||
fn visit_ty(&mut self, t: Ty<'tcx>) { | ||
if t == self.pointee { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this implementation "micro-optimized"? It shouldn't matter to override all these functions, and it makes the visitor much larger than it needs to be. |
||
self.found = true; | ||
} else { | ||
t.super_visit_with(self) | ||
} | ||
} | ||
} | ||
let mut search = Search { pointee: target_pointee_ty, found: false }; | ||
ty.visit_with(&mut search); | ||
search.found | ||
} | ||
|
||
#[instrument(level = "debug", skip(tcx))] | ||
pub(super) fn redact_fulfillment_err_for_coerce_pointee<'tcx>( | ||
tcx: TyCtxt<'tcx>, | ||
err: FulfillmentError<'tcx>, | ||
target_pointee_ty: Ty<'tcx>, | ||
span: Span, | ||
) -> Option<FulfillmentError<'tcx>> { | ||
if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) = | ||
err.obligation.predicate.kind().skip_binder() | ||
{ | ||
let mentions_pointee = || { | ||
contains_coerce_pointee_target_pointee( | ||
pred.trait_ref.args.type_at(1), | ||
target_pointee_ty, | ||
) | ||
}; | ||
let source = pred.trait_ref.self_ty(); | ||
if tcx.is_lang_item(pred.def_id(), LangItem::DispatchFromDyn) && mentions_pointee() { | ||
tcx.dcx().emit_err(errors::CoercePointeeCannotDispatchFromDyn { | ||
ty: source.to_string(), | ||
span, | ||
}); | ||
return None; | ||
} | ||
if tcx.is_lang_item(pred.def_id(), LangItem::Unsize) && mentions_pointee() { | ||
// We should redact it | ||
tcx.dcx().emit_err(errors::CoercePointeeCannotUnsize { ty: source.to_string(), span }); | ||
return None; | ||
} | ||
if tcx.is_lang_item(pred.def_id(), LangItem::CoerceUnsized) && mentions_pointee() { | ||
// We should redact it | ||
tcx.dcx() | ||
.emit_err(errors::CoercePointeeCannotCoerceUnsize { ty: source.to_string(), span }); | ||
return None; | ||
} | ||
} | ||
Some(err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This note is not exercised by any test, I think?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just realised that the note cannot be exercised because the span falls within the macro expansion.
Instead it is overwritten by this message.
This happens still after adding the missing
#[note]
and#[help]
attributes to the diagnostics.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I need to switch to the span of the ADT definition.