Auto merge of #134353 - oli-obk:safe-target-feature-unsafe-by-default, r=wesleywiser
Treat safe target_feature functions as unsafe by default [less invasive variant] This unblocks * #134090 As I stated in https://github.com/rust-lang/rust/pull/134090#issuecomment-2541332415 I think the previous impl was too easy to get wrong, as by default it treated safe target feature functions as safe and had to add additional checks for when they weren't. Now the logic is inverted. By default they are unsafe and you have to explicitly handle safe target feature functions. This is the less (imo) invasive variant of #134317, as it doesn't require changing the Safety enum, so it only affects FnDefs and nothing else, as it should.
This commit is contained in:
commit
341f60327f
39 changed files with 319 additions and 120 deletions
|
@ -824,9 +824,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
fn cmp_fn_sig(
|
||||
&self,
|
||||
sig1: &ty::PolyFnSig<'tcx>,
|
||||
fn_def1: Option<(DefId, &'tcx [ty::GenericArg<'tcx>])>,
|
||||
fn_def1: Option<(DefId, Option<&'tcx [ty::GenericArg<'tcx>]>)>,
|
||||
sig2: &ty::PolyFnSig<'tcx>,
|
||||
fn_def2: Option<(DefId, &'tcx [ty::GenericArg<'tcx>])>,
|
||||
fn_def2: Option<(DefId, Option<&'tcx [ty::GenericArg<'tcx>]>)>,
|
||||
) -> (DiagStyledString, DiagStyledString) {
|
||||
let sig1 = &(self.normalize_fn_sig)(*sig1);
|
||||
let sig2 = &(self.normalize_fn_sig)(*sig2);
|
||||
|
@ -850,8 +850,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
|
||||
// ^^^^^^
|
||||
values.0.push(sig1.safety.prefix_str(), sig1.safety != sig2.safety);
|
||||
values.1.push(sig2.safety.prefix_str(), sig1.safety != sig2.safety);
|
||||
let safety = |fn_def, sig: ty::FnSig<'_>| match fn_def {
|
||||
None => sig.safety.prefix_str(),
|
||||
Some((did, _)) => {
|
||||
if self.tcx.codegen_fn_attrs(did).safe_target_features {
|
||||
"#[target_features] "
|
||||
} else {
|
||||
sig.safety.prefix_str()
|
||||
}
|
||||
}
|
||||
};
|
||||
let safety1 = safety(fn_def1, sig1);
|
||||
let safety2 = safety(fn_def2, sig2);
|
||||
values.0.push(safety1, safety1 != safety2);
|
||||
values.1.push(safety2, safety1 != safety2);
|
||||
|
||||
// unsafe extern "C" for<'a> fn(&'a T) -> &'a T
|
||||
// ^^^^^^^^^^
|
||||
|
@ -932,23 +944,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
(values.1).0.extend(x2.0);
|
||||
}
|
||||
|
||||
let fmt = |(did, args)| format!(" {{{}}}", self.tcx.def_path_str_with_args(did, args));
|
||||
let fmt = |did, args| format!(" {{{}}}", self.tcx.def_path_str_with_args(did, args));
|
||||
|
||||
match (fn_def1, fn_def2) {
|
||||
(None, None) => {}
|
||||
(Some(fn_def1), Some(fn_def2)) => {
|
||||
let path1 = fmt(fn_def1);
|
||||
let path2 = fmt(fn_def2);
|
||||
(Some((fn_def1, Some(fn_args1))), Some((fn_def2, Some(fn_args2)))) => {
|
||||
let path1 = fmt(fn_def1, fn_args1);
|
||||
let path2 = fmt(fn_def2, fn_args2);
|
||||
let same_path = path1 == path2;
|
||||
values.0.push(path1, !same_path);
|
||||
values.1.push(path2, !same_path);
|
||||
}
|
||||
(Some(fn_def1), None) => {
|
||||
values.0.push_highlighted(fmt(fn_def1));
|
||||
(Some((fn_def1, Some(fn_args1))), None) => {
|
||||
values.0.push_highlighted(fmt(fn_def1, fn_args1));
|
||||
}
|
||||
(None, Some(fn_def2)) => {
|
||||
values.1.push_highlighted(fmt(fn_def2));
|
||||
(None, Some((fn_def2, Some(fn_args2)))) => {
|
||||
values.1.push_highlighted(fmt(fn_def2, fn_args2));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
values
|
||||
|
@ -1339,17 +1351,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
(ty::FnDef(did1, args1), ty::FnDef(did2, args2)) => {
|
||||
let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
|
||||
let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
|
||||
self.cmp_fn_sig(&sig1, Some((*did1, args1)), &sig2, Some((*did2, args2)))
|
||||
self.cmp_fn_sig(
|
||||
&sig1,
|
||||
Some((*did1, Some(args1))),
|
||||
&sig2,
|
||||
Some((*did2, Some(args2))),
|
||||
)
|
||||
}
|
||||
|
||||
(ty::FnDef(did1, args1), ty::FnPtr(sig_tys2, hdr2)) => {
|
||||
let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
|
||||
self.cmp_fn_sig(&sig1, Some((*did1, args1)), &sig_tys2.with(*hdr2), None)
|
||||
self.cmp_fn_sig(&sig1, Some((*did1, Some(args1))), &sig_tys2.with(*hdr2), None)
|
||||
}
|
||||
|
||||
(ty::FnPtr(sig_tys1, hdr1), ty::FnDef(did2, args2)) => {
|
||||
let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
|
||||
self.cmp_fn_sig(&sig_tys1.with(*hdr1), None, &sig2, Some((*did2, args2)))
|
||||
self.cmp_fn_sig(&sig_tys1.with(*hdr1), None, &sig2, Some((*did2, Some(args2))))
|
||||
}
|
||||
|
||||
(ty::FnPtr(sig_tys1, hdr1), ty::FnPtr(sig_tys2, hdr2)) => {
|
||||
|
@ -1531,7 +1548,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
(false, Mismatch::Fixed("existential projection"))
|
||||
}
|
||||
};
|
||||
let Some(vals) = self.values_str(values) else {
|
||||
let Some(vals) = self.values_str(values, cause) else {
|
||||
// Derived error. Cancel the emitter.
|
||||
// NOTE(eddyb) this was `.cancel()`, but `diag`
|
||||
// is borrowed, so we can't fully defuse it.
|
||||
|
@ -1956,7 +1973,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
})
|
||||
| ObligationCauseCode::BlockTailExpression(.., source)) = code
|
||||
&& let hir::MatchSource::TryDesugar(_) = source
|
||||
&& let Some((expected_ty, found_ty, _)) = self.values_str(trace.values)
|
||||
&& let Some((expected_ty, found_ty, _)) = self.values_str(trace.values, &trace.cause)
|
||||
{
|
||||
suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert {
|
||||
found: found_ty.content(),
|
||||
|
@ -2085,6 +2102,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
fn values_str(
|
||||
&self,
|
||||
values: ValuePairs<'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
) -> Option<(DiagStyledString, DiagStyledString, Option<PathBuf>)> {
|
||||
match values {
|
||||
ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found),
|
||||
|
@ -2109,7 +2127,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
if exp_found.references_error() {
|
||||
return None;
|
||||
}
|
||||
let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, None, &exp_found.found, None);
|
||||
let (fn_def1, fn_def2) = if let ObligationCauseCode::CompareImplItem {
|
||||
impl_item_def_id,
|
||||
trait_item_def_id,
|
||||
..
|
||||
} = *cause.code()
|
||||
{
|
||||
(Some((trait_item_def_id, None)), Some((impl_item_def_id.to_def_id(), None)))
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let (exp, fnd) =
|
||||
self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2);
|
||||
Some((exp, fnd, None))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -461,9 +461,11 @@ impl<T> Trait<T> for X {
|
|||
(ty::FnPtr(_, hdr), ty::FnDef(def_id, _))
|
||||
| (ty::FnDef(def_id, _), ty::FnPtr(_, hdr)) => {
|
||||
if tcx.fn_sig(def_id).skip_binder().safety() < hdr.safety {
|
||||
diag.note(
|
||||
if !tcx.codegen_fn_attrs(def_id).safe_target_features {
|
||||
diag.note(
|
||||
"unsafe functions cannot be coerced into safe function pointers",
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
(ty::Adt(_, _), ty::Adt(def, args))
|
||||
|
|
|
@ -221,7 +221,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
|
||||
span: trace.cause.span,
|
||||
requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
|
||||
expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)),
|
||||
expected_found: self.values_str(trace.values, &trace.cause).map(|(e, f, _)| (e, f)),
|
||||
}
|
||||
.add_to_diag(err),
|
||||
infer::Reborrow(span) => {
|
||||
|
@ -946,8 +946,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
|
||||
if let infer::Subtype(ref sup_trace) = sup_origin
|
||||
&& let infer::Subtype(ref sub_trace) = sub_origin
|
||||
&& let Some((sup_expected, sup_found, _)) = self.values_str(sup_trace.values)
|
||||
&& let Some((sub_expected, sub_found, _)) = self.values_str(sub_trace.values)
|
||||
&& let Some((sup_expected, sup_found, _)) =
|
||||
self.values_str(sup_trace.values, &sup_trace.cause)
|
||||
&& let Some((sub_expected, sub_found, _)) =
|
||||
self.values_str(sub_trace.values, &sup_trace.cause)
|
||||
&& sub_expected == sup_expected
|
||||
&& sub_found == sup_found
|
||||
{
|
||||
|
|
|
@ -205,9 +205,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
|||
|
||||
if self_ty.is_fn() {
|
||||
let fn_sig = self_ty.fn_sig(self.tcx);
|
||||
let shortname = match fn_sig.safety() {
|
||||
hir::Safety::Safe => "fn",
|
||||
hir::Safety::Unsafe => "unsafe fn",
|
||||
let shortname = if let ty::FnDef(def_id, _) = self_ty.kind()
|
||||
&& self.tcx.codegen_fn_attrs(def_id).safe_target_features
|
||||
{
|
||||
"#[target_feature] fn"
|
||||
} else {
|
||||
match fn_sig.safety() {
|
||||
hir::Safety::Safe => "fn",
|
||||
hir::Safety::Unsafe => "unsafe fn",
|
||||
}
|
||||
};
|
||||
flags.push((sym::_Self, Some(shortname.to_owned())));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue