Fix up tests
This commit is contained in:
parent
5193c211ea
commit
73d49f8c69
@ -82,6 +82,10 @@ struct Coerce<'a, 'tcx> {
|
|||||||
/// See #47489 and #48598
|
/// See #47489 and #48598
|
||||||
/// See docs on the "AllowTwoPhase" type for a more detailed discussion
|
/// See docs on the "AllowTwoPhase" type for a more detailed discussion
|
||||||
allow_two_phase: AllowTwoPhase,
|
allow_two_phase: AllowTwoPhase,
|
||||||
|
/// Whether we allow `NeverToAny` coercions. This is unsound if we're
|
||||||
|
/// coercing a place expression without it counting as a read in the MIR.
|
||||||
|
/// This is a side-effect of HIR not really having a great distinction
|
||||||
|
/// between places and values.
|
||||||
coerce_never: bool,
|
coerce_never: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1083,7 +1087,8 @@ pub(crate) fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
|
|||||||
debug!("coercion::can_with_predicates({:?} -> {:?})", source, target);
|
debug!("coercion::can_with_predicates({:?} -> {:?})", source, target);
|
||||||
|
|
||||||
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
||||||
// We don't ever need two-phase here since we throw out the result of the coercion
|
// We don't ever need two-phase here since we throw out the result of the coercion.
|
||||||
|
// We also just always set `coerce_never` to true, since this is a heuristic.
|
||||||
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
|
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
|
||||||
self.probe(|_| {
|
self.probe(|_| {
|
||||||
let Ok(ok) = coerce.coerce(source, target) else {
|
let Ok(ok) = coerce.coerce(source, target) else {
|
||||||
@ -1096,11 +1101,15 @@ pub(crate) fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Given a type and a target type, this function will calculate and return
|
/// Given a type and a target type, this function will calculate and return
|
||||||
/// how many dereference steps needed to achieve `expr_ty <: target`. If
|
/// how many dereference steps needed to coerce `expr_ty` to `target`. If
|
||||||
/// it's not possible, return `None`.
|
/// it's not possible, return `None`.
|
||||||
pub(crate) fn deref_steps(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> Option<usize> {
|
pub(crate) fn deref_steps_for_suggestion(
|
||||||
|
&self,
|
||||||
|
expr_ty: Ty<'tcx>,
|
||||||
|
target: Ty<'tcx>,
|
||||||
|
) -> Option<usize> {
|
||||||
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
|
||||||
// We don't ever need two-phase here since we throw out the result of the coercion
|
// We don't ever need two-phase here since we throw out the result of the coercion.
|
||||||
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
|
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
|
||||||
coerce
|
coerce
|
||||||
.autoderef(DUMMY_SP, expr_ty)
|
.autoderef(DUMMY_SP, expr_ty)
|
||||||
|
@ -2608,7 +2608,7 @@ pub(crate) fn suggest_deref_or_ref(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind
|
if let hir::ExprKind::Unary(hir::UnOp::Deref, inner) = expr.kind
|
||||||
&& let Some(1) = self.deref_steps(expected, checked_ty)
|
&& let Some(1) = self.deref_steps_for_suggestion(expected, checked_ty)
|
||||||
{
|
{
|
||||||
// We have `*&T`, check if what was expected was `&T`.
|
// We have `*&T`, check if what was expected was `&T`.
|
||||||
// If so, we may want to suggest removing a `*`.
|
// If so, we may want to suggest removing a `*`.
|
||||||
@ -2738,7 +2738,7 @@ pub(crate) fn suggest_deref_or_ref(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
(_, &ty::RawPtr(ty_b, mutbl_b), &ty::Ref(_, ty_a, mutbl_a)) => {
|
(_, &ty::RawPtr(ty_b, mutbl_b), &ty::Ref(_, ty_a, mutbl_a)) => {
|
||||||
if let Some(steps) = self.deref_steps(ty_a, ty_b)
|
if let Some(steps) = self.deref_steps_for_suggestion(ty_a, ty_b)
|
||||||
// Only suggest valid if dereferencing needed.
|
// Only suggest valid if dereferencing needed.
|
||||||
&& steps > 0
|
&& steps > 0
|
||||||
// The pointer type implements `Copy` trait so the suggestion is always valid.
|
// The pointer type implements `Copy` trait so the suggestion is always valid.
|
||||||
@ -2782,7 +2782,7 @@ pub(crate) fn suggest_deref_or_ref(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if sp == expr.span => {
|
_ if sp == expr.span => {
|
||||||
if let Some(mut steps) = self.deref_steps(checked_ty, expected) {
|
if let Some(mut steps) = self.deref_steps_for_suggestion(checked_ty, expected) {
|
||||||
let mut expr = expr.peel_blocks();
|
let mut expr = expr.peel_blocks();
|
||||||
let mut prefix_span = expr.span.shrink_to_lo();
|
let mut prefix_span = expr.span.shrink_to_lo();
|
||||||
let mut remove = String::new();
|
let mut remove = String::new();
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// Various tests ensuring that underscore patterns really just construct the place, but don't check its contents.
|
// Various tests ensuring that underscore patterns really just construct the place, but don't check its contents.
|
||||||
#![feature(strict_provenance)]
|
#![feature(strict_provenance)]
|
||||||
|
#![feature(never_type)]
|
||||||
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -9,6 +11,7 @@ fn main() {
|
|||||||
invalid_let();
|
invalid_let();
|
||||||
dangling_let_type_annotation();
|
dangling_let_type_annotation();
|
||||||
invalid_let_type_annotation();
|
invalid_let_type_annotation();
|
||||||
|
never();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dangling_match() {
|
fn dangling_match() {
|
||||||
@ -34,6 +37,13 @@ union Uninit<T: Copy> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let x: Uninit<!> = Uninit { uninit: () };
|
||||||
|
match x.value {
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dangling_let() {
|
fn dangling_let() {
|
||||||
@ -41,6 +51,11 @@ fn dangling_let() {
|
|||||||
let ptr = ptr::without_provenance::<bool>(0x40);
|
let ptr = ptr::without_provenance::<bool>(0x40);
|
||||||
let _ = *ptr;
|
let _ = *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let ptr = ptr::without_provenance::<!>(0x40);
|
||||||
|
let _ = *ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invalid_let() {
|
fn invalid_let() {
|
||||||
@ -49,6 +64,12 @@ fn invalid_let() {
|
|||||||
let ptr = ptr::addr_of!(val).cast::<bool>();
|
let ptr = ptr::addr_of!(val).cast::<bool>();
|
||||||
let _ = *ptr;
|
let _ = *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let val = 3u8;
|
||||||
|
let ptr = ptr::addr_of!(val).cast::<!>();
|
||||||
|
let _ = *ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Adding a type annotation used to change how MIR is generated, make sure we cover both cases.
|
// Adding a type annotation used to change how MIR is generated, make sure we cover both cases.
|
||||||
@ -57,6 +78,11 @@ fn dangling_let_type_annotation() {
|
|||||||
let ptr = ptr::without_provenance::<bool>(0x40);
|
let ptr = ptr::without_provenance::<bool>(0x40);
|
||||||
let _: bool = *ptr;
|
let _: bool = *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let ptr = ptr::without_provenance::<!>(0x40);
|
||||||
|
let _: ! = *ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invalid_let_type_annotation() {
|
fn invalid_let_type_annotation() {
|
||||||
@ -65,7 +91,28 @@ fn invalid_let_type_annotation() {
|
|||||||
let ptr = ptr::addr_of!(val).cast::<bool>();
|
let ptr = ptr::addr_of!(val).cast::<bool>();
|
||||||
let _: bool = *ptr;
|
let _: bool = *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let val = 3u8;
|
||||||
|
let ptr = ptr::addr_of!(val).cast::<!>();
|
||||||
|
let _: ! = *ptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: we should also test `!`, not just `bool` -- but that s currently buggy:
|
// Regression test from <https://github.com/rust-lang/rust/issues/117288>.
|
||||||
// https://github.com/rust-lang/rust/issues/117288
|
fn never() {
|
||||||
|
unsafe {
|
||||||
|
let x = 3u8;
|
||||||
|
let x: *const ! = &x as *const u8 as *const _;
|
||||||
|
let _: ! = *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Without a type annotation, make sure we don't implicitly coerce `!` to `()`
|
||||||
|
// when we do the noop `*x` (as that would require a `!` *value*, creating
|
||||||
|
// which is UB).
|
||||||
|
unsafe {
|
||||||
|
let x = 3u8;
|
||||||
|
let x: *const ! = &x as *const u8 as *const _;
|
||||||
|
let _ = *x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
// MIR for `main` after SimplifyLocals-final
|
||||||
|
|
||||||
|
fn main() -> () {
|
||||||
|
let mut _0: ();
|
||||||
|
let _1: u8;
|
||||||
|
let mut _2: *const !;
|
||||||
|
let mut _3: *const u8;
|
||||||
|
let _4: u8;
|
||||||
|
let mut _5: *const !;
|
||||||
|
let mut _6: *const u8;
|
||||||
|
scope 1 {
|
||||||
|
debug x => _1;
|
||||||
|
scope 2 {
|
||||||
|
debug x => _2;
|
||||||
|
scope 3 {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scope 4 {
|
||||||
|
debug x => _4;
|
||||||
|
scope 5 {
|
||||||
|
debug x => _5;
|
||||||
|
scope 6 {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bb0: {
|
||||||
|
StorageLive(_1);
|
||||||
|
_1 = const 3_u8;
|
||||||
|
StorageLive(_2);
|
||||||
|
StorageLive(_3);
|
||||||
|
_3 = &raw const _1;
|
||||||
|
_2 = move _3 as *const ! (PtrToPtr);
|
||||||
|
StorageDead(_3);
|
||||||
|
StorageDead(_2);
|
||||||
|
StorageDead(_1);
|
||||||
|
StorageLive(_4);
|
||||||
|
_4 = const 3_u8;
|
||||||
|
StorageLive(_5);
|
||||||
|
StorageLive(_6);
|
||||||
|
_6 = &raw const _4;
|
||||||
|
_5 = move _6 as *const ! (PtrToPtr);
|
||||||
|
StorageDead(_6);
|
||||||
|
StorageDead(_5);
|
||||||
|
StorageDead(_4);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
27
tests/mir-opt/uninhabited_not_read.rs
Normal file
27
tests/mir-opt/uninhabited_not_read.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// skip-filecheck
|
||||||
|
|
||||||
|
//@ edition: 2021
|
||||||
|
// In ed 2021 and below, we don't fallback `!` to `()`.
|
||||||
|
// This would introduce a `! -> ()` coercion which would
|
||||||
|
// be UB if we didn't disallow this explicitly.
|
||||||
|
|
||||||
|
#![feature(never_type)]
|
||||||
|
|
||||||
|
// EMIT_MIR uninhabited_not_read.main.SimplifyLocals-final.after.mir
|
||||||
|
fn main() {
|
||||||
|
// With a type annotation
|
||||||
|
unsafe {
|
||||||
|
let x = 3u8;
|
||||||
|
let x: *const ! = &x as *const u8 as *const _;
|
||||||
|
let _: ! = *x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Without a type annotation, make sure we don't implicitly coerce `!` to `()`
|
||||||
|
// when we do the noop `*x`.
|
||||||
|
unsafe {
|
||||||
|
let x = 3u8;
|
||||||
|
let x: *const ! = &x as *const u8 as *const _;
|
||||||
|
let _ = *x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
|
|
||||||
fn make_up_a_value<T>() -> T {
|
fn not_a_read() -> ! {
|
||||||
unsafe {
|
unsafe {
|
||||||
//~^ ERROR mismatched types
|
//~^ ERROR mismatched types
|
||||||
let x: *const ! = 0 as _;
|
let x: *const ! = 0 as _;
|
||||||
@ -10,4 +10,38 @@ fn make_up_a_value<T>() -> T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn not_a_read_implicit() -> ! {
|
||||||
|
unsafe {
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
let x: *const ! = 0 as _;
|
||||||
|
let _ = *x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn not_a_read_guide_coercion() -> ! {
|
||||||
|
unsafe {
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
let x: *const ! = 0 as _;
|
||||||
|
let _: () = *x;
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn empty_match() -> ! {
|
||||||
|
unsafe {
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
let x: *const ! = 0 as _;
|
||||||
|
match *x { _ => {} };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn field_projection() -> ! {
|
||||||
|
unsafe {
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
let x: *const (!, ()) = 0 as _;
|
||||||
|
let _ = (*x).0;
|
||||||
|
// ^ I think this is still UB, but because of the inbounds projection.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/diverging-place-match.rs:4:5
|
--> $DIR/diverging-place-match.rs:4:5
|
||||||
|
|
|
|
||||||
LL | fn make_up_a_value<T>() -> T {
|
|
||||||
| - expected this type parameter
|
|
||||||
LL | / unsafe {
|
LL | / unsafe {
|
||||||
LL | |
|
LL | |
|
||||||
LL | | let x: *const ! = 0 as _;
|
LL | | let x: *const ! = 0 as _;
|
||||||
@ -10,11 +8,76 @@ LL | | let _: ! = *x;
|
|||||||
LL | | // Since `*x` "diverges" in HIR, but doesn't count as a read in MIR, this
|
LL | | // Since `*x` "diverges" in HIR, but doesn't count as a read in MIR, this
|
||||||
LL | | // is unsound since we act as if it diverges but it doesn't.
|
LL | | // is unsound since we act as if it diverges but it doesn't.
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^ expected type parameter `T`, found `()`
|
| |_____^ expected `!`, found `()`
|
||||||
|
|
|
|
||||||
= note: expected type parameter `T`
|
= note: expected type `!`
|
||||||
found unit type `()`
|
found unit type `()`
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/diverging-place-match.rs:14:5
|
||||||
|
|
|
||||||
|
LL | / unsafe {
|
||||||
|
LL | |
|
||||||
|
LL | | let x: *const ! = 0 as _;
|
||||||
|
LL | | let _ = *x;
|
||||||
|
LL | | }
|
||||||
|
| |_____^ expected `!`, found `()`
|
||||||
|
|
|
||||||
|
= note: expected type `!`
|
||||||
|
found unit type `()`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/diverging-place-match.rs:25:21
|
||||||
|
|
|
||||||
|
LL | let _: () = *x;
|
||||||
|
| -- ^^ expected `()`, found `!`
|
||||||
|
| |
|
||||||
|
| expected due to this
|
||||||
|
|
|
||||||
|
= note: expected unit type `()`
|
||||||
|
found type `!`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/diverging-place-match.rs:22:5
|
||||||
|
|
|
||||||
|
LL | / unsafe {
|
||||||
|
LL | |
|
||||||
|
LL | | let x: *const ! = 0 as _;
|
||||||
|
LL | | let _: () = *x;
|
||||||
|
LL | |
|
||||||
|
LL | | }
|
||||||
|
| |_____^ expected `!`, found `()`
|
||||||
|
|
|
||||||
|
= note: expected type `!`
|
||||||
|
found unit type `()`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/diverging-place-match.rs:31:5
|
||||||
|
|
|
||||||
|
LL | / unsafe {
|
||||||
|
LL | |
|
||||||
|
LL | | let x: *const ! = 0 as _;
|
||||||
|
LL | | match *x { _ => {} };
|
||||||
|
LL | | }
|
||||||
|
| |_____^ expected `!`, found `()`
|
||||||
|
|
|
||||||
|
= note: expected type `!`
|
||||||
|
found unit type `()`
|
||||||
|
|
||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/diverging-place-match.rs:39:5
|
||||||
|
|
|
||||||
|
LL | / unsafe {
|
||||||
|
LL | |
|
||||||
|
LL | | let x: *const (!, ()) = 0 as _;
|
||||||
|
LL | | let _ = (*x).0;
|
||||||
|
LL | | // ^ I think this is still UB, but because of the inbounds projection.
|
||||||
|
LL | | }
|
||||||
|
| |_____^ expected `!`, found `()`
|
||||||
|
|
|
||||||
|
= note: expected type `!`
|
||||||
|
found unit type `()`
|
||||||
|
|
||||||
|
error: aborting due to 6 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0308`.
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
|
Loading…
Reference in New Issue
Block a user