Skip to content

Implement Mutation- and BorrowOfLayoutConstrainedField in thir-unsafeck #86665

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

Merged
merged 1 commit into from
Jul 13, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/build/expr/mod.rs
Original file line number Diff line number Diff line change
@@ -65,6 +65,6 @@ mod as_operand;
pub mod as_place;
mod as_rvalue;
mod as_temp;
mod category;
pub mod category;
mod into;
mod stmt;
2 changes: 2 additions & 0 deletions compiler/rustc_mir_build/src/build/mod.rs
Original file line number Diff line number Diff line change
@@ -1131,3 +1131,5 @@ mod expr;
mod matches;
mod misc;
mod scope;

pub(crate) use expr::category::Category as ExprCategory;
197 changes: 150 additions & 47 deletions compiler/rustc_mir_build/src/check_unsafety.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::build::ExprCategory;
use crate::thir::visit::{self, Visitor};

use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_middle::mir::BorrowKind;
use rustc_middle::thir::*;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::ty::{self, ParamEnv, 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};
@@ -28,6 +30,8 @@ struct UnsafetyVisitor<'a, 'tcx> {
is_const: bool,
in_possible_lhs_union_assign: bool,
in_union_destructure: bool,
param_env: ParamEnv<'tcx>,
inside_adt: bool,
}

impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
@@ -134,6 +138,50 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
}
}

// Searches for accesses to layout constrained fields.
struct LayoutConstrainedPlaceVisitor<'a, 'tcx> {
found: bool,
thir: &'a Thir<'tcx>,
tcx: TyCtxt<'tcx>,
}

impl<'a, 'tcx> LayoutConstrainedPlaceVisitor<'a, 'tcx> {
fn new(thir: &'a Thir<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
Self { found: false, thir, tcx }
}
}

impl<'a, 'tcx> Visitor<'a, 'tcx> for LayoutConstrainedPlaceVisitor<'a, 'tcx> {
fn thir(&self) -> &'a Thir<'tcx> {
self.thir
}

fn visit_expr(&mut self, expr: &Expr<'tcx>) {
match expr.kind {
ExprKind::Field { lhs, .. } => {
if let ty::Adt(adt_def, _) = self.thir[lhs].ty.kind() {
if (Bound::Unbounded, Bound::Unbounded)
!= self.tcx.layout_scalar_valid_range(adt_def.did)
{
self.found = true;
}
}
visit::walk_expr(self, expr);
}

// Keep walking through the expression as long as we stay in the same
// place, i.e. the expression is a place expression and not a dereference
// (since dereferencing something leads us to a different place).
ExprKind::Deref { .. } => {}
ref kind if ExprCategory::of(kind).map_or(true, |cat| cat == ExprCategory::Place) => {
visit::walk_expr(self, expr);
}

_ => {}
}
}
}

impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
fn thir(&self) -> &'a Thir<'tcx> {
&self.thir
@@ -161,60 +209,82 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
}

fn visit_pat(&mut self, pat: &Pat<'tcx>) {
use PatKind::*;

if self.in_union_destructure {
match *pat.kind {
// binding to a variable allows getting stuff out of variable
Binding { .. }
PatKind::Binding { .. }
// match is conditional on having this value
| Constant { .. }
| Variant { .. }
| Leaf { .. }
| Deref { .. }
| Range { .. }
| Slice { .. }
| Array { .. } => {
| PatKind::Constant { .. }
| PatKind::Variant { .. }
| PatKind::Leaf { .. }
| PatKind::Deref { .. }
| PatKind::Range { .. }
| PatKind::Slice { .. }
| PatKind::Array { .. } => {
self.requires_unsafe(pat.span, AccessToUnionField);
return; // don't walk pattern
return; // we can return here since this already requires unsafe
}
// wildcard doesn't take anything
Wild |
PatKind::Wild |
// these just wrap other patterns
Or { .. } |
AscribeUserType { .. } => {}
PatKind::Or { .. } |
PatKind::AscribeUserType { .. } => {}
}
};

if let ty::Adt(adt_def, _) = pat.ty.kind() {
// check for extracting values from union via destructuring
if adt_def.is_union() {
match *pat.kind {
// assigning the whole union is okay
// let x = Union { ... };
// let y = x; // safe
Binding { .. } |
// binding to wildcard is okay since that never reads anything and stops double errors
// with implict wildcard branches from `if let`s
Wild |
// doesn't have any effect on semantics
AscribeUserType { .. } |
// creating a union literal
Constant { .. } => {},
Leaf { .. } | Or { .. } => {
// pattern matching with a union and not doing something like v = Union { bar: 5 }
self.in_union_destructure = true;
match &*pat.kind {
PatKind::Leaf { .. } => {
if let ty::Adt(adt_def, ..) = pat.ty.kind() {
if adt_def.is_union() {
let old_in_union_destructure =
std::mem::replace(&mut self.in_union_destructure, true);
visit::walk_pat(self, pat);
self.in_union_destructure = old_in_union_destructure;
} else if (Bound::Unbounded, Bound::Unbounded)
!= self.tcx.layout_scalar_valid_range(adt_def.did)
{
let old_inside_adt = std::mem::replace(&mut self.inside_adt, true);
visit::walk_pat(self, pat);
self.inside_adt = old_inside_adt;
} else {
visit::walk_pat(self, pat);
self.in_union_destructure = false;
return; // don't walk pattern
}
Variant { .. } | Deref { .. } | Range { .. } | Slice { .. } | Array { .. } =>
unreachable!("impossible union destructuring type"),
} else {
visit::walk_pat(self, pat);
}
}
PatKind::Binding { mode: BindingMode::ByRef(borrow_kind), ty, .. } => {
if self.inside_adt {
if let ty::Ref(_, ty, _) = ty.kind() {
match borrow_kind {
BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) {
self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
}
}
BorrowKind::Mut { .. } => {
self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField);
}
}
} else {
span_bug!(
pat.span,
"BindingMode::ByRef in pattern, but found non-reference type {}",
ty
);
}
}
visit::walk_pat(self, pat);
}
PatKind::Deref { .. } => {
let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
visit::walk_pat(self, pat);
self.inside_adt = old_inside_adt;
}
_ => {
visit::walk_pat(self, pat);
}
}

visit::walk_pat(self, pat);
}

fn visit_expr(&mut self, expr: &Expr<'tcx>) {
@@ -361,15 +431,46 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
}
}
}
// don't have any special handling for AssignOp since it causes a read *and* write to lhs
ExprKind::Assign { lhs, rhs } => {
// assigning to a union is safe, check here so it doesn't get treated as a read later
self.in_possible_lhs_union_assign = true;
visit::walk_expr(self, &self.thir()[lhs]);
self.in_possible_lhs_union_assign = false;
visit::walk_expr(self, &self.thir()[rhs]);
return; // don't visit the whole expression
ExprKind::Assign { lhs, rhs } | ExprKind::AssignOp { lhs, rhs, .. } => {
// First, check whether we are mutating a layout constrained field
let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
visit::walk_expr(&mut visitor, &self.thir[lhs]);
if visitor.found {
self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField);
}

// Second, check for accesses to union fields
// don't have any special handling for AssignOp since it causes a read *and* write to lhs
if matches!(expr.kind, ExprKind::Assign { .. }) {
// assigning to a union is safe, check here so it doesn't get treated as a read later
self.in_possible_lhs_union_assign = true;
visit::walk_expr(self, &self.thir()[lhs]);
self.in_possible_lhs_union_assign = false;
visit::walk_expr(self, &self.thir()[rhs]);
return; // we have already visited everything by now
}
}
ExprKind::Borrow { borrow_kind, arg } => match borrow_kind {
BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
if !self.thir[arg]
.ty
.is_freeze(self.tcx.at(self.thir[arg].span), self.param_env)
{
let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
visit::walk_expr(&mut visitor, expr);
if visitor.found {
self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField);
}
}
}
BorrowKind::Mut { .. } => {
let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
visit::walk_expr(&mut visitor, expr);
if visitor.found {
self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField);
}
}
},
_ => {}
}
visit::walk_expr(self, expr);
@@ -541,6 +642,8 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalD
is_const,
in_possible_lhs_union_assign: false,
in_union_destructure: false,
param_env: tcx.param_env(def.did),
inside_adt: false,
};
visitor.visit_expr(&thir[expr]);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/ranged_ints2.rs:8:13
--> $DIR/ranged_ints2.rs:11:13
|
LL | let y = &mut x.0;
| ^^^^^^^^ mutation of layout constrained field
3 changes: 3 additions & 0 deletions src/test/ui/unsafe/ranged_ints2.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck

#![feature(rustc_attrs)]

#[rustc_layout_scalar_valid_range_start(1)]
11 changes: 11 additions & 0 deletions src/test/ui/unsafe/ranged_ints2.thirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/ranged_ints2.rs:11:13
|
LL | let y = &mut x.0;
| ^^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error: aborting due to previous error

For more information about this error, try `rustc --explain E0133`.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0658]: mutable references are not allowed in constant functions
--> $DIR/ranged_ints2_const.rs:11:13
--> $DIR/ranged_ints2_const.rs:14:13
|
LL | let y = &mut x.0;
| ^^^^^^^^
@@ -8,7 +8,7 @@ LL | let y = &mut x.0;
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

error[E0658]: mutable references are not allowed in constant functions
--> $DIR/ranged_ints2_const.rs:18:22
--> $DIR/ranged_ints2_const.rs:21:22
|
LL | let y = unsafe { &mut x.0 };
| ^^^^^^^^
@@ -17,7 +17,7 @@ LL | let y = unsafe { &mut x.0 };
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

error[E0658]: mutable references are not allowed in constant functions
--> $DIR/ranged_ints2_const.rs:24:22
--> $DIR/ranged_ints2_const.rs:27:22
|
LL | unsafe { let y = &mut x.0; }
| ^^^^^^^^
@@ -26,7 +26,7 @@ LL | unsafe { let y = &mut x.0; }
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/ranged_ints2_const.rs:11:13
--> $DIR/ranged_ints2_const.rs:14:13
|
LL | let y = &mut x.0;
| ^^^^^^^^ mutation of layout constrained field
3 changes: 3 additions & 0 deletions src/test/ui/unsafe/ranged_ints2_const.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck

#![feature(rustc_attrs)]

#[rustc_layout_scalar_valid_range_start(1)]
39 changes: 39 additions & 0 deletions src/test/ui/unsafe/ranged_ints2_const.thirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/ranged_ints2_const.rs:14:13
|
LL | let y = &mut x.0;
| ^^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error[E0658]: mutable references are not allowed in constant functions
--> $DIR/ranged_ints2_const.rs:14:13
|
LL | let y = &mut x.0;
| ^^^^^^^^
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

error[E0658]: mutable references are not allowed in constant functions
--> $DIR/ranged_ints2_const.rs:21:22
|
LL | let y = unsafe { &mut x.0 };
| ^^^^^^^^
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

error[E0658]: mutable references are not allowed in constant functions
--> $DIR/ranged_ints2_const.rs:27:22
|
LL | unsafe { let y = &mut x.0; }
| ^^^^^^^^
|
= note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
= help: add `#![feature(const_mut_refs)]` to the crate attributes to enable

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0133, E0658.
For more information about an error, try `rustc --explain E0133`.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
--> $DIR/ranged_ints3.rs:10:13
--> $DIR/ranged_ints3.rs:13:13
|
LL | let y = &x.0;
| ^^^^ borrow of layout constrained field with interior mutability
3 changes: 3 additions & 0 deletions src/test/ui/unsafe/ranged_ints3.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck

#![feature(rustc_attrs)]

use std::cell::Cell;
11 changes: 11 additions & 0 deletions src/test/ui/unsafe/ranged_ints3.thirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
--> $DIR/ranged_ints3.rs:13:13
|
LL | let y = &x.0;
| ^^^^ borrow of layout constrained field with interior mutability
|
= note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values

error: aborting due to previous error

For more information about this error, try `rustc --explain E0133`.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
--> $DIR/ranged_ints3_const.rs:12:13
--> $DIR/ranged_ints3_const.rs:15:13
|
LL | let y = &x.0;
| ^^^^
@@ -8,7 +8,7 @@ LL | let y = &x.0;
= help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable

error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
--> $DIR/ranged_ints3_const.rs:19:22
--> $DIR/ranged_ints3_const.rs:22:22
|
LL | let y = unsafe { &x.0 };
| ^^^^
@@ -17,7 +17,7 @@ LL | let y = unsafe { &x.0 };
= help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable

error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
--> $DIR/ranged_ints3_const.rs:12:13
--> $DIR/ranged_ints3_const.rs:15:13
|
LL | let y = &x.0;
| ^^^^ borrow of layout constrained field with interior mutability
3 changes: 3 additions & 0 deletions src/test/ui/unsafe/ranged_ints3_const.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck

#![feature(rustc_attrs)]

use std::cell::Cell;
30 changes: 30 additions & 0 deletions src/test/ui/unsafe/ranged_ints3_const.thirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
--> $DIR/ranged_ints3_const.rs:15:13
|
LL | let y = &x.0;
| ^^^^ borrow of layout constrained field with interior mutability
|
= note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values

error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
--> $DIR/ranged_ints3_const.rs:15:13
|
LL | let y = &x.0;
| ^^^^
|
= note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
= help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable

error[E0658]: cannot borrow here, since the borrowed element may contain interior mutability
--> $DIR/ranged_ints3_const.rs:22:22
|
LL | let y = unsafe { &x.0 };
| ^^^^
|
= note: see issue #80384 <https://github.com/rust-lang/rust/issues/80384> for more information
= help: add `#![feature(const_refs_to_cell)]` to the crate attributes to enable

error: aborting due to 3 previous errors

Some errors have detailed explanations: E0133, E0658.
For more information about an error, try `rustc --explain E0133`.
19 changes: 19 additions & 0 deletions src/test/ui/unsafe/ranged_ints3_match.mirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
--> $DIR/ranged_ints3_match.rs:14:17
|
LL | NonZero(ref x) => { x }
| ^^^^^ borrow of layout constrained field with interior mutability
|
= note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values

error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/ranged_ints3_match.rs:20:23
|
LL | match y { NonZero(ref mut y) => { y } };
| ^^^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0133`.
22 changes: 22 additions & 0 deletions src/test/ui/unsafe/ranged_ints3_match.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck

#![feature(rustc_attrs)]

use std::cell::Cell;

#[rustc_layout_scalar_valid_range_start(1)]
#[repr(transparent)]
pub(crate) struct NonZero<T>(pub(crate) T);
fn main() {
let mut x = unsafe { NonZero(Cell::new(1)) };
match x {
NonZero(ref x) => { x }
//~^ ERROR borrow of layout constrained field with interior mutability
};

let mut y = unsafe { NonZero(42) };
match y { NonZero(ref y) => { y } }; // OK, type of `y` is freeze
match y { NonZero(ref mut y) => { y } };
//~^ ERROR mutation of layout constrained field
}
19 changes: 19 additions & 0 deletions src/test/ui/unsafe/ranged_ints3_match.thirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0133]: borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
--> $DIR/ranged_ints3_match.rs:14:17
|
LL | NonZero(ref x) => { x }
| ^^^^^ borrow of layout constrained field with interior mutability
|
= note: references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values

error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/ranged_ints3_match.rs:20:23
|
LL | match y { NonZero(ref mut y) => { y } };
| ^^^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0133`.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/ranged_ints4.rs:8:5
--> $DIR/ranged_ints4.rs:11:5
|
LL | x.0 = 0;
| ^^^^^^^ mutation of layout constrained field
3 changes: 3 additions & 0 deletions src/test/ui/unsafe/ranged_ints4.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck

#![feature(rustc_attrs)]

#[rustc_layout_scalar_valid_range_start(1)]
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/ranged_ints4_const.rs:10:5
--> $DIR/ranged_ints4.rs:11:5
|
LL | x.0 = 0;
| ^^^^^^^ mutation of layout constrained field
11 changes: 11 additions & 0 deletions src/test/ui/unsafe/ranged_ints4_const.mirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/ranged_ints4_const.rs:13:5
|
LL | x.0 = 0;
| ^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error: aborting due to previous error

For more information about this error, try `rustc --explain E0133`.
3 changes: 3 additions & 0 deletions src/test/ui/unsafe/ranged_ints4_const.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck

#![feature(rustc_attrs)]

#[rustc_layout_scalar_valid_range_start(1)]
11 changes: 11 additions & 0 deletions src/test/ui/unsafe/ranged_ints4_const.thirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/ranged_ints4_const.rs:13:5
|
LL | x.0 = 0;
| ^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error: aborting due to previous error

For more information about this error, try `rustc --explain E0133`.
11 changes: 11 additions & 0 deletions src/test/ui/unsafe/unsafe-assign.mirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/unsafe-assign.rs:12:5
|
LL | foo.0.0 = 0;
| ^^^^^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error: aborting due to previous error

For more information about this error, try `rustc --explain E0133`.
25 changes: 25 additions & 0 deletions src/test/ui/unsafe/unsafe-assign.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck

#![feature(rustc_attrs)]
#![allow(unused,dead_code)]

fn nested_field() {
#[rustc_layout_scalar_valid_range_start(1)]
struct NonZero<T>(T);

let mut foo = unsafe { NonZero((1,)) };
foo.0.0 = 0;
//~^ ERROR: mutation of layout constrained field is unsafe
}

fn block() {
#[rustc_layout_scalar_valid_range_start(1)]
struct NonZero<T>(T);

let mut foo = unsafe { NonZero((1,)) };
{ foo.0 }.0 = 0;
// ^ not unsafe because the result of the block expression is a new place
}

fn main() {}
11 changes: 11 additions & 0 deletions src/test/ui/unsafe/unsafe-assign.thirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/unsafe-assign.rs:12:5
|
LL | foo.0.0 = 0;
| ^^^^^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error: aborting due to previous error

For more information about this error, try `rustc --explain E0133`.
27 changes: 27 additions & 0 deletions src/test/ui/unsafe/unsafe-borrow.mirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/unsafe-borrow.rs:12:13
|
LL | let a = &mut foo.0.0;
| ^^^^^^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/unsafe-borrow.rs:32:13
|
LL | let a = &mut foo.0[2];
| ^^^^^^^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/unsafe-borrow.rs:51:18
|
LL | NonZero((a,)) => *a = 0,
| ^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0133`.
56 changes: 56 additions & 0 deletions src/test/ui/unsafe/unsafe-borrow.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck

#![feature(rustc_attrs)]
#![allow(unused,dead_code)]

fn tuple_struct() {
#[rustc_layout_scalar_valid_range_start(1)]
struct NonZero<T>(T);

let mut foo = unsafe { NonZero((1,)) };
let a = &mut foo.0.0;
//~^ ERROR: mutation of layout constrained field is unsafe
}

fn slice() {
#[rustc_layout_scalar_valid_range_start(1)]
struct NonZero<'a, T>(&'a mut [T]);

let mut nums = [1, 2, 3, 4];
let mut foo = unsafe { NonZero(&mut nums[..]) };
let a = &mut foo.0[2];
// ^ not unsafe because there is an implicit dereference here
}

fn array() {
#[rustc_layout_scalar_valid_range_start(1)]
struct NonZero<T>([T; 4]);

let nums = [1, 2, 3, 4];
let mut foo = unsafe { NonZero(nums) };
let a = &mut foo.0[2];
//~^ ERROR: mutation of layout constrained field is unsafe
}

fn block() {
#[rustc_layout_scalar_valid_range_start(1)]
struct NonZero<T>(T);

let foo = unsafe { NonZero((1,)) };
&mut { foo.0 }.0;
// ^ not unsafe because the result of the block expression is a new place
}

fn mtch() {
#[rustc_layout_scalar_valid_range_start(1)]
struct NonZero<T>(T);

let mut foo = unsafe { NonZero((1,)) };
match &mut foo {
NonZero((a,)) => *a = 0,
//~^ ERROR: mutation of layout constrained field is unsafe
}
}

fn main() {}
27 changes: 27 additions & 0 deletions src/test/ui/unsafe/unsafe-borrow.thirunsafeck.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/unsafe-borrow.rs:12:13
|
LL | let a = &mut foo.0.0;
| ^^^^^^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/unsafe-borrow.rs:32:13
|
LL | let a = &mut foo.0[2];
| ^^^^^^^^^^^^^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block
--> $DIR/unsafe-borrow.rs:51:18
|
LL | NonZero((a,)) => *a = 0,
| ^ mutation of layout constrained field
|
= note: mutating layout constrained fields cannot statically be checked for valid values

error: aborting due to 3 previous errors

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