Skip to content

Commit

Permalink
Check for calls to functions with #[target_feature] in THIR unsafeck
Browse files Browse the repository at this point in the history
  • Loading branch information
LeSeulArtichaut committed May 19, 2021
1 parent 27fe959 commit d7787bb
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 15 deletions.
31 changes: 27 additions & 4 deletions compiler/rustc_mir_build/src/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
use rustc_session::lint::Level;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::symbol::Symbol;
use rustc_span::Span;

struct UnsafetyVisitor<'a, 'tcx> {
Expand All @@ -19,6 +20,9 @@ struct UnsafetyVisitor<'a, 'tcx> {
/// `unsafe` block, and whether it has been used.
safety_context: SafetyContext,
body_unsafety: BodyUnsafety,
/// The `#[target_feature]` attributes of the body. Used for checking
/// calls to functions with `#[target_feature]` (RFC 2396).
body_target_features: &'tcx Vec<Symbol>,
}

impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
Expand Down Expand Up @@ -148,6 +152,18 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
self.requires_unsafe(expr.span, CallToUnsafeFunction);
} else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() {
// If the called function has target features the calling function hasn't,
// the call requires `unsafe`.
if !self
.tcx
.codegen_fn_attrs(func_did)
.target_features
.iter()
.all(|feature| self.body_target_features.contains(feature))
{
self.requires_unsafe(expr.span, CallToFunctionWith);
}
}
}
ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => {
Expand Down Expand Up @@ -217,7 +233,6 @@ enum UnsafeOpKind {
MutationOfLayoutConstrainedField,
#[allow(dead_code)] // FIXME
BorrowOfLayoutConstrainedField,
#[allow(dead_code)] // FIXME
CallToFunctionWith,
}

Expand Down Expand Up @@ -291,6 +306,7 @@ pub fn check_unsafety<'tcx>(
tcx: TyCtxt<'tcx>,
thir: &Thir<'tcx>,
expr: ExprId,
def_id: LocalDefId,
hir_id: hir::HirId,
) {
let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| {
Expand All @@ -300,10 +316,17 @@ pub fn check_unsafety<'tcx>(
BodyUnsafety::Safe
}
});
let body_target_features = &tcx.codegen_fn_attrs(def_id).target_features;
let safety_context =
if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
let mut visitor =
UnsafetyVisitor { tcx, thir, safety_context, hir_context: hir_id, body_unsafety };
let mut visitor = UnsafetyVisitor {
tcx,
thir,
safety_context,
hir_context: hir_id,
body_unsafety,
body_target_features,
};
visitor.visit_expr(&thir[expr]);
}

Expand All @@ -315,7 +338,7 @@ crate fn thir_check_unsafety_inner<'tcx>(
let body_id = tcx.hir().body_owned_by(hir_id);
let body = tcx.hir().body(body_id);
let (thir, expr) = cx::build_thir(tcx, def, &body.value);
check_unsafety(tcx, &thir, expr, hir_id);
check_unsafety(tcx, &thir, expr, def.did, hir_id);
}

crate fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

// check-pass
// only-x86_64
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck

#![feature(target_feature_11)]

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Tests #73631: closures inherit `#[target_feature]` annotations

// check-pass
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck
// only-x86_64

#![feature(target_feature_11)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
--> $DIR/fn-ptr.rs:9:21
--> $DIR/fn-ptr.rs:11:21
|
LL | #[target_feature(enable = "sse2")]
| ---------------------------------- `#[target_feature]` added here
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck
// only-x86_64

#![feature(target_feature_11)]
Expand Down
18 changes: 18 additions & 0 deletions src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
error[E0308]: mismatched types
--> $DIR/fn-ptr.rs:11:21
|
LL | #[target_feature(enable = "sse2")]
| ---------------------------------- `#[target_feature]` added here
...
LL | let foo: fn() = foo;
| ---- ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers
| |
| expected due to this
|
= note: expected fn pointer `fn()`
found fn item `fn() {foo}`
= note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
Original file line number Diff line number Diff line change
@@ -1,77 +1,77 @@
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:21:5
--> $DIR/safe-calls.rs:23:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:22:5
--> $DIR/safe-calls.rs:24:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:23:5
--> $DIR/safe-calls.rs:25:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:28:5
--> $DIR/safe-calls.rs:30:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:29:5
--> $DIR/safe-calls.rs:31:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:34:5
--> $DIR/safe-calls.rs:36:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:35:5
--> $DIR/safe-calls.rs:37:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:36:5
--> $DIR/safe-calls.rs:38:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:42:5
--> $DIR/safe-calls.rs:44:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:45:18
--> $DIR/safe-calls.rs:47:18
|
LL | const name: () = sse2();
| ^^^^^^ call to function with `#[target_feature]`
Expand Down
2 changes: 2 additions & 0 deletions src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// revisions: mir thir
// [thir]compile-flags: -Z thir-unsafeck
// only-x86_64

#![feature(target_feature_11)]
Expand Down
83 changes: 83 additions & 0 deletions src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:23:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:24:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:25:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:30:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:31:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:36:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:37:5
|
LL | avx_bmi2();
| ^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:38:5
|
LL | Quux.avx_bmi2();
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:44:5
|
LL | sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block
--> $DIR/safe-calls.rs:47:18
|
LL | const name: () = sse2();
| ^^^^^^ call to function with `#[target_feature]`
|
= note: can only be called if the required target features are available

error: aborting due to 10 previous errors

For more information about this error, try `rustc --explain E0133`.

0 comments on commit d7787bb

Please sign in to comment.