Skip to content

Commit 341f603

Browse files
committed
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 #134090 (comment) 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.
2 parents 2776bdf + 767d4fe commit 341f603

39 files changed

Lines changed: 319 additions & 120 deletions

File tree

‎compiler/rustc_ast_lowering/src/delegation.rs‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
188188
) -> hir::FnSig<'hir>{
189189
let header = ifletSome(local_sig_id) = sig_id.as_local(){
190190
matchself.resolver.delegation_fn_sigs.get(&local_sig_id){
191-
Some(sig) => self.lower_fn_header(sig.header, hir::Safety::Safe),
191+
Some(sig) => self.lower_fn_header(
192+
sig.header,
193+
// HACK: we override the default safety instead of generating attributes from the ether.
194+
// We are not forwarding the attributes, as the delegation fn sigs are collected on the ast,
195+
// and here we need the hir attributes.
196+
if sig.target_feature{ hir::Safety::Unsafe}else{ hir::Safety::Safe},
197+
&[],
198+
),
192199
None => self.generate_header_error(),
193200
}
194201
}else{
@@ -198,7 +205,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
198205
Asyncness::No => hir::IsAsync::NotAsync,
199206
};
200207
hir::FnHeader{
201-
safety: sig.safety,
208+
safety:ifself.tcx.codegen_fn_attrs(sig_id).safe_target_features{
209+
hir::HeaderSafety::SafeTargetFeatures
210+
}else{
211+
hir::HeaderSafety::Normal(sig.safety)
212+
},
202213
constness:self.tcx.constness(sig_id),
203214
asyncness,
204215
abi: sig.abi,
@@ -384,7 +395,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
384395

385396
fngenerate_header_error(&self) -> hir::FnHeader{
386397
hir::FnHeader{
387-
safety: hir::Safety::Safe,
398+
safety: hir::Safety::Safe.into(),
388399
constness: hir::Constness::NotConst,
389400
asyncness: hir::IsAsync::NotAsync,
390401
abi: abi::Abi::Rust,

‎compiler/rustc_ast_lowering/src/item.rs‎

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
231231
});
232232
let sig = hir::FnSig{
233233
decl,
234-
header: this.lower_fn_header(*header, hir::Safety::Safe),
234+
header: this.lower_fn_header(*header, hir::Safety::Safe, attrs),
235235
span: this.lower_span(*fn_sig_span),
236236
};
237237
hir::ItemKind::Fn{ sig, generics,body: body_id,has_body: body.is_some()}
@@ -610,7 +610,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
610610
fnlower_foreign_item(&mutself,i:&ForeignItem) -> &'hir hir::ForeignItem<'hir>{
611611
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
612612
let owner_id = hir_id.expect_owner();
613-
self.lower_attrs(hir_id,&i.attrs);
613+
let attrs = self.lower_attrs(hir_id,&i.attrs);
614614
let item = hir::ForeignItem{
615615
owner_id,
616616
ident:self.lower_ident(i.ident),
@@ -634,7 +634,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
634634
});
635635

636636
// Unmarked safety in unsafe block defaults to unsafe.
637-
let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe);
637+
let header = self.lower_fn_header(sig.header, hir::Safety::Unsafe, attrs);
638638

639639
hir::ForeignItemKind::Fn(
640640
hir::FnSig{ header, decl,span:self.lower_span(sig.span)},
@@ -776,6 +776,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
776776
i.id,
777777
FnDeclKind::Trait,
778778
sig.header.coroutine_kind,
779+
attrs,
779780
);
780781
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)),false)
781782
}
@@ -795,6 +796,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
795796
i.id,
796797
FnDeclKind::Trait,
797798
sig.header.coroutine_kind,
799+
attrs,
798800
);
799801
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)),true)
800802
}
@@ -911,6 +913,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
911913
i.id,
912914
ifself.is_in_trait_impl{FnDeclKind::Impl}else{FnDeclKind::Inherent},
913915
sig.header.coroutine_kind,
916+
attrs,
914917
);
915918

916919
(generics, hir::ImplItemKind::Fn(sig, body_id))
@@ -1339,8 +1342,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
13391342
id:NodeId,
13401343
kind:FnDeclKind,
13411344
coroutine_kind:Option<CoroutineKind>,
1345+
attrs:&[hir::Attribute],
13421346
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>){
1343-
let header = self.lower_fn_header(sig.header, hir::Safety::Safe);
1347+
let header = self.lower_fn_header(sig.header, hir::Safety::Safe, attrs);
13441348
let itctx = ImplTraitContext::Universal;
13451349
let(generics, decl) = self.lower_generics(generics, id, itctx, |this| {
13461350
this.lower_fn_decl(&sig.decl, id, sig.span, kind, coroutine_kind)
@@ -1352,14 +1356,28 @@ impl<'hir> LoweringContext<'_, 'hir> {
13521356
&mutself,
13531357
h:FnHeader,
13541358
default_safety: hir::Safety,
1359+
attrs:&[hir::Attribute],
13551360
) -> hir::FnHeader{
13561361
let asyncness = ifletSome(CoroutineKind::Async{ span, .. }) = h.coroutine_kind{
13571362
hir::IsAsync::Async(span)
13581363
}else{
13591364
hir::IsAsync::NotAsync
13601365
};
1366+
1367+
let safety = self.lower_safety(h.safety, default_safety);
1368+
1369+
// Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so.
1370+
let safety = if attrs.iter().any(|attr| attr.has_name(sym::target_feature))
1371+
&& safety.is_safe()
1372+
&& !self.tcx.sess.target.is_like_wasm
1373+
{
1374+
hir::HeaderSafety::SafeTargetFeatures
1375+
}else{
1376+
safety.into()
1377+
};
1378+
13611379
hir::FnHeader{
1362-
safety:self.lower_safety(h.safety, default_safety),
1380+
safety,
13631381
asyncness,
13641382
constness:self.lower_constness(h.constness),
13651383
abi:self.lower_extern(h.ext),

‎compiler/rustc_codegen_ssa/src/codegen_attrs.rs‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
250250
}
251251
}
252252
sym::target_feature => {
253-
if !tcx.is_closure_like(did.to_def_id())
254-
&& letSome(fn_sig) = fn_sig()
255-
&& fn_sig.skip_binder().safety().is_safe()
256-
{
253+
letSome(sig) = tcx.hir_node_by_def_id(did).fn_sig()else{
254+
tcx.dcx().span_delayed_bug(attr.span,"target_feature applied to non-fn");
255+
continue;
256+
};
257+
let safe_target_features =
258+
matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures);
259+
codegen_fn_attrs.safe_target_features = safe_target_features;
260+
if safe_target_features {
257261
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc{
258262
// The `#[target_feature]` attribute is allowed on
259263
// WebAssembly targets on all functions, including safe

‎compiler/rustc_hir/src/hir.rs‎

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3762,9 +3762,30 @@ impl fmt::Display for Constness {
37623762
}
37633763
}
37643764

3765+
/// The actualy safety specified in syntax. We may treat
3766+
/// its safety different within the type system to create a
3767+
/// "sound by default" system that needs checking this enum
3768+
/// explicitly to allow unsafe operations.
3769+
#[derive(Copy,Clone,Debug,HashStable_Generic,PartialEq,Eq)]
3770+
pubenumHeaderSafety{
3771+
/// A safe function annotated with `#[target_features]`.
3772+
/// The type system treats this function as an unsafe function,
3773+
/// but safety checking will check this enum to treat it as safe
3774+
/// and allowing calling other safe target feature functions with
3775+
/// the same features without requiring an additional unsafe block.
3776+
SafeTargetFeatures,
3777+
Normal(Safety),
3778+
}
3779+
3780+
implFrom<Safety>forHeaderSafety{
3781+
fnfrom(v:Safety) -> Self{
3782+
Self::Normal(v)
3783+
}
3784+
}
3785+
37653786
#[derive(Copy,Clone,Debug,HashStable_Generic)]
37663787
pubstructFnHeader{
3767-
pubsafety:Safety,
3788+
pubsafety:HeaderSafety,
37683789
pubconstness:Constness,
37693790
pubasyncness:IsAsync,
37703791
pubabi:ExternAbi,
@@ -3780,7 +3801,18 @@ impl FnHeader {
37803801
}
37813802

37823803
pubfnis_unsafe(&self) -> bool{
3783-
self.safety.is_unsafe()
3804+
self.safety().is_unsafe()
3805+
}
3806+
3807+
pubfnis_safe(&self) -> bool{
3808+
self.safety().is_safe()
3809+
}
3810+
3811+
pubfnsafety(&self) -> Safety{
3812+
matchself.safety{
3813+
HeaderSafety::SafeTargetFeatures => Safety::Unsafe,
3814+
HeaderSafety::Normal(safety) => safety,
3815+
}
37843816
}
37853817
}
37863818

‎compiler/rustc_hir_analysis/src/collect.rs‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,7 +1336,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
13361336
{
13371337
icx.lowerer().lower_fn_ty(
13381338
hir_id,
1339-
sig.header.safety,
1339+
sig.header.safety(),
13401340
sig.header.abi,
13411341
sig.decl,
13421342
Some(generics),
@@ -1351,13 +1351,18 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn
13511351
kind:TraitItemKind::Fn(FnSig{ header, decl,span: _ }, _),
13521352
generics,
13531353
..
1354-
}) => {
1355-
icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl,Some(generics),None)
1356-
}
1354+
}) => icx.lowerer().lower_fn_ty(
1355+
hir_id,
1356+
header.safety(),
1357+
header.abi,
1358+
decl,
1359+
Some(generics),
1360+
None,
1361+
),
13571362

13581363
ForeignItem(&hir::ForeignItem{kind:ForeignItemKind::Fn(sig, _, _), .. }) => {
13591364
let abi = tcx.hir().get_foreign_abi(hir_id);
1360-
compute_sig_of_foreign_fn_decl(tcx, def_id, sig.decl, abi, sig.header.safety)
1365+
compute_sig_of_foreign_fn_decl(tcx, def_id, sig.decl, abi, sig.header.safety())
13611366
}
13621367

13631368
Ctor(data) | Variant(hir::Variant{ data, .. })if data.ctor().is_some() => {
@@ -1405,7 +1410,7 @@ fn lower_fn_sig_recovering_infer_ret_ty<'tcx>(
14051410

14061411
icx.lowerer().lower_fn_ty(
14071412
icx.tcx().local_def_id_to_hir_id(def_id),
1408-
sig.header.safety,
1413+
sig.header.safety(),
14091414
sig.header.abi,
14101415
sig.decl,
14111416
Some(generics),

‎compiler/rustc_hir_pretty/src/lib.rs‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2407,7 +2407,7 @@ impl<'a> State<'a> {
24072407
self.print_fn(
24082408
decl,
24092409
hir::FnHeader{
2410-
safety,
2410+
safety: safety.into(),
24112411
abi,
24122412
constness: hir::Constness::NotConst,
24132413
asyncness: hir::IsAsync::NotAsync,
@@ -2423,12 +2423,20 @@ impl<'a> State<'a> {
24232423
fnprint_fn_header_info(&mutself,header: hir::FnHeader){
24242424
self.print_constness(header.constness);
24252425

2426+
let safety = match header.safety{
2427+
hir::HeaderSafety::SafeTargetFeatures => {
2428+
self.word_nbsp("#[target_feature]");
2429+
hir::Safety::Safe
2430+
}
2431+
hir::HeaderSafety::Normal(safety) => safety,
2432+
};
2433+
24262434
match header.asyncness{
24272435
hir::IsAsync::NotAsync => {}
24282436
hir::IsAsync::Async(_) => self.word_nbsp("async"),
24292437
}
24302438

2431-
self.print_safety(header.safety);
2439+
self.print_safety(safety);
24322440

24332441
if header.abi != ExternAbi::Rust{
24342442
self.word_nbsp("extern");

‎compiler/rustc_hir_typeck/src/coercion.rs‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -932,10 +932,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
932932
returnErr(TypeError::ForceInlineCast);
933933
}
934934

935-
// Safe `#[target_feature]` functions are not assignable to safe fn pointers
936-
// (RFC 2396).
935+
let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
936+
ifmatches!(fn_attrs.inline,InlineAttr::Force{ .. }){
937+
returnErr(TypeError::ForceInlineCast);
938+
}
939+
940+
// FIXME(target_feature): Safe `#[target_feature]` functions could be cast to safe fn pointers (RFC 2396),
941+
// as you can already write that "cast" in user code by wrapping a target_feature fn call in a closure,
942+
// which is safe. This is sound because you already need to be executing code that is satisfying the target
943+
// feature constraints..
937944
if b_hdr.safety.is_safe()
938-
&& !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
945+
&& self.tcx.codegen_fn_attrs(def_id).safe_target_features
939946
{
940947
returnErr(TypeError::TargetFeatureCast(def_id));
941948
}

‎compiler/rustc_hir_typeck/src/lib.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ fn typeck_with_fallback<'tcx>(
139139
// type that has an infer in it, lower the type directly so that it'll
140140
// be correctly filled with infer. We'll use this inference to provide
141141
// a suggestion later on.
142-
fcx.lowerer().lower_fn_ty(id, header.safety, header.abi, decl,None,None)
142+
fcx.lowerer().lower_fn_ty(id, header.safety(), header.abi, decl,None,None)
143143
}else{
144144
tcx.fn_sig(def_id).instantiate_identity()
145145
};

‎compiler/rustc_middle/src/middle/codegen_fn_attrs.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ pub struct CodegenFnAttrs {
3030
/// features (only enabled features are supported right now).
3131
/// Implied target features have already been applied.
3232
pubtarget_features:Vec<TargetFeature>,
33+
/// Whether the function was declared safe, but has target features
34+
pubsafe_target_features:bool,
3335
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
3436
publinkage:Option<Linkage>,
3537
/// The `#[linkage = "..."]` attribute on foreign items and the value we found.
@@ -150,6 +152,7 @@ impl CodegenFnAttrs {
150152
link_name:None,
151153
link_ordinal:None,
152154
target_features:vec![],
155+
safe_target_features:false,
153156
linkage:None,
154157
import_linkage:None,
155158
link_section:None,

‎compiler/rustc_middle/src/ty/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ pub struct DelegationFnSig {
222222
pubparam_count:usize,
223223
pubhas_self:bool,
224224
pubc_variadic:bool,
225+
pubtarget_feature:bool,
225226
}
226227

227228
#[derive(Clone,Copy,Debug)]

0 commit comments

Comments
 (0)