Skip to content
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

Check if call return type is visibly uninhabited when building MIR #93313

Merged
merged 1 commit into from
Apr 20, 2022
Merged
Show file tree
Hide file tree
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
13 changes: 9 additions & 4 deletions compiler/rustc_mir_build/src/build/expr/into.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
func: fun,
args,
cleanup: None,
// FIXME(varkor): replace this with an uninhabitedness-based check.
// This requires getting access to the current module to call
// `tcx.is_ty_uninhabited_from`, which is currently tricky to do.
destination: if expr.ty.is_never() {
// The presence or absence of a return edge affects control-flow sensitive
// MIR checks and ultimately whether code is accepted or not. We can only
// omit the return edge if a return type is visibly uninhabited to a module
// that makes the call.
destination: if this.tcx.is_ty_uninhabited_from(
this.parent_module,
wesleywiser marked this conversation as resolved.
Show resolved Hide resolved
expr.ty,
this.param_env,
) {
None
} else {
Some((destination, success))
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_mir_build/src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,7 @@ struct Builder<'a, 'tcx> {

def_id: DefId,
hir_id: hir::HirId,
parent_module: DefId,
check_overflow: bool,
fn_span: Span,
arg_count: usize,
Expand Down Expand Up @@ -807,15 +808,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);

let lint_level = LintLevel::Explicit(hir_id);
let param_env = tcx.param_env(def.did);
let mut builder = Builder {
thir,
tcx,
infcx,
typeck_results: tcx.typeck_opt_const_arg(def),
region_scope_tree: tcx.region_scope_tree(def.did),
param_env: tcx.param_env(def.did),
param_env,
def_id: def.did.to_def_id(),
hir_id,
parent_module: tcx.parent_module(hir_id).to_def_id(),
check_overflow,
cfg: CFG { basic_blocks: IndexVec::new() },
fn_span: span,
Expand Down
2 changes: 1 addition & 1 deletion src/test/codegen/set-discriminant-invalid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl IntoError<Error> for Api
#[no_mangle]
fn into_error(self, error: Self::Source) -> Error {
Error::Api {
source: (|v| v)(error),
source: error,
}
}
}
Expand Down
49 changes: 24 additions & 25 deletions src/test/mir-opt/inline/inline_diverging.h.Inline.diff
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@
fn h() -> () {
let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:21:12: 21:12
let _1: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+ let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+ let mut _9: (); // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16
+ let mut _10: (); // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16
+ let mut _2: (!, !); // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+ let mut _3: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+ let mut _10: (); // in scope 0 at $DIR/inline-diverging.rs:27:13: 27:16
+ let mut _11: (); // in scope 0 at $DIR/inline-diverging.rs:28:13: 28:16
+ scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22
+ debug f => _2; // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
+ let _3: !; // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
+ let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
+ let mut _6: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
+ let mut _7: !; // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
+ let mut _8: !; // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
+ debug f => _3; // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
+ let _4: !; // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
+ let mut _5: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
+ let mut _7: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
+ let mut _8: !; // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
+ let mut _9: !; // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
+ scope 2 {
+ debug a => _3; // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
+ let _5: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
+ debug a => _4; // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
+ let _6: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
+ scope 3 {
+ debug b => _5; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
+ debug b => _6; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
+ }
+ scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:28:13: 28:16
+ scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
Expand All @@ -33,27 +34,25 @@

bb0: {
StorageLive(_1); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
- _1 = call_twice::<!, fn() -> ! {sleep}>(sleep) -> bb1; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
- call_twice::<!, fn() -> ! {sleep}>(sleep); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+ StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+ _2 = sleep; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+ StorageLive(_3); // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
+ _3 = sleep; // scope 0 at $DIR/inline-diverging.rs:22:5: 22:22
// mir::Constant
- // + span: $DIR/inline-diverging.rs:22:5: 22:15
- // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice::<!, fn() -> ! {sleep}>}, val: Value(Scalar(<ZST>)) }
- // mir::Constant
// + span: $DIR/inline-diverging.rs:22:16: 22:21
// + literal: Const { ty: fn() -> ! {sleep}, val: Value(Scalar(<ZST>)) }
+ StorageLive(_3); // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
+ StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
+ _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
+ StorageLive(_9); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
+ _9 = const (); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
+ StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
+ StorageLive(_5); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
+ _5 = &_3; // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
+ StorageLive(_10); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
+ _10 = const (); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
}

bb1: {
- StorageDead(_1); // scope 0 at $DIR/inline-diverging.rs:22:22: 22:23
- _0 = const (); // scope 0 at $DIR/inline-diverging.rs:21:12: 23:2
- return; // scope 0 at $DIR/inline-diverging.rs:23:2: 23:2
+ }
+
+ bb1: {
+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/mir-opt/issue_72181_1.main.mir_map.0.mir
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn main() -> () {
StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10
StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
_3 = (); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43
_2 = transmute::<(), Void>(move _3) -> [return: bb1, unwind: bb4]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44
// mir::Constant
// + span: $DIR/issue-72181-1.rs:17:9: 17:40
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(Scalar(<ZST>)) }
Expand Down
22 changes: 6 additions & 16 deletions src/test/ui/consts/const-eval/ub-enum.32bit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -119,27 +119,17 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran
78 00 00 00 ff ff ff ff │ x.......
}

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:92:1
error[E0080]: evaluation of constant value failed
--> $DIR/ub-enum.rs:92:77
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
00 00 00 00 00 00 00 00 │ ........
}
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:94:1
error[E0080]: evaluation of constant value failed
--> $DIR/ub-enum.rs:94:77
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
00 00 00 00 00 00 00 00 │ ........
}
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type

error: aborting due to 13 previous errors

Expand Down
22 changes: 6 additions & 16 deletions src/test/ui/consts/const-eval/ub-enum.64bit.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -119,27 +119,17 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran
78 00 00 00 ff ff ff ff │ x.......
}

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:92:1
error[E0080]: evaluation of constant value failed
--> $DIR/ub-enum.rs:92:77
|
LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of uninhabited type Never
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
00 00 00 00 00 00 00 00 │ ........
}
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type

error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-enum.rs:94:1
error[E0080]: evaluation of constant value failed
--> $DIR/ub-enum.rs:94:77
|
LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<enum-variant(Ok)>.0.1: encountered a value of the never type `!`
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 4) {
00 00 00 00 00 00 00 00 │ ........
}
| ^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type

error: aborting due to 13 previous errors

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/consts/const-eval/ub-enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute
// All variants are uninhabited but also have data.
// Use `0` as constant to make behavior endianess-independent.
const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) };
//~^ ERROR is undefined behavior
//~^ ERROR evaluation of constant value failed
const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) };
//~^ ERROR is undefined behavior
//~^ ERROR evaluation of constant value failed

fn main() {
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@ LL | unsafe { std::mem::transmute(()) }
LL | const FOO: [Empty; 3] = [foo(); 3];
| ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26

error[E0080]: it is undefined behavior to use this value
--> $DIR/validate_uninhabited_zsts.rs:16:1
error[E0080]: evaluation of constant value failed
--> $DIR/validate_uninhabited_zsts.rs:16:35
|
LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a somewhat unfortunate reduction in test coverage for validity (we now error much earlier during evaluation)... ideally this would be adjusted to transmute to a type that is not 'visibly' uninhabited so that we still test the same code paths as before.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did the same in a Miri test so that type definition can probably just be copied.

= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 0, align: 1) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type

warning: the type `!` does not permit zero-initialization
--> $DIR/validate_uninhabited_zsts.rs:4:14
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@ LL | unsafe { std::mem::transmute(()) }
LL | const FOO: [Empty; 3] = [foo(); 3];
| ----- inside `FOO` at $DIR/validate_uninhabited_zsts.rs:13:26

error[E0080]: it is undefined behavior to use this value
--> $DIR/validate_uninhabited_zsts.rs:16:1
error[E0080]: evaluation of constant value failed
--> $DIR/validate_uninhabited_zsts.rs:16:35
|
LL | const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at [0]: encountered a value of uninhabited type Empty
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 0, align: 1) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type

warning: the type `!` does not permit zero-initialization
--> $DIR/validate_uninhabited_zsts.rs:4:14
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/consts/const-eval/validate_uninhabited_zsts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const FOO: [Empty; 3] = [foo(); 3];

#[warn(const_err)]
const BAR: [Empty; 3] = [unsafe { std::mem::transmute(()) }; 3];
//~^ ERROR it is undefined behavior to use this value
//~^ ERROR evaluation of constant value failed
//~| WARN the type `Empty` does not permit zero-initialization

fn main() {
Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/generator/issue-93161.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// edition:2021
// run-pass
// compile-flags: -Zdrop-tracking

#![feature(never_type)]

Expand Down Expand Up @@ -32,7 +33,7 @@ fn never() -> Never {
}

async fn includes_never(crash: bool, x: u32) -> u32 {
let mut result = async { x * x }.await;
let result = async { x * x }.await;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior change seems correct, but I wonder if we need to be concerned from a compatibility perspective?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear: Wesley's assumption is that the unused mut lint started firing here (because the mutation of result falls after the call to never() below, and so that's why the PR author has removed the mut.

And Wesley's question is: Do we need to worry about this? Considering e.g. code that might have #![deny(unused_mut)], and now it starts seeing that as an error.

(My personal answer is that lints are allowed to change their behavior in this manner. I'm currently double-checking/asking around for examples from Rust's past.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The lint side of things seems fine to me from compatibility perspective. It is
not unusual for us to adjust how lints work, and practical impact is limited by
cargo capping the lint level for dependencies.

The fact that we would now accept more programs seems more significant, since
it would be a breaking change to revert. Though, as far as I can see, we did in
fact accept those programs after #54125 landed, but have since regressed after
switching to MIR borrowck.

Copy link
Member

@RalfJung RalfJung Apr 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It also seems surprising that this mut would be unused, since result is mutated in later code -- in a regular function, we are not that smart wrt unused-mut warnings, or are we?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was talking about this with @scottmcm a little while back and he found this example: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=26220b66188903b1dd8f3325960f75af

That version compiles even though x is mutated, since the mutation comes after the panic. Although, for me making it let mut x doesn't raise an unused mut warning. Anyway, I think this shows prior art for being clever about things being mutated only in unreachable code, so this change seems to make things more uniform.

if !crash {
return result;
}
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/statics/uninhabited-static.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ extern {

static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
//~| ERROR undefined behavior to use this value
//~| ERROR could not evaluate static initializer
//~| WARN: type `Void` does not permit zero-initialization
static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
//~| ERROR undefined behavior to use this value
//~| ERROR could not evaluate static initializer
//~| WARN: type `Void` does not permit zero-initialization

fn main() {}
18 changes: 6 additions & 12 deletions src/test/ui/statics/uninhabited-static.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,17 @@ LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
= note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840>
= note: uninhabited statics cannot be initialized, and any access would be an immediate error

error[E0080]: it is undefined behavior to use this value
--> $DIR/uninhabited-static.rs:12:1
error[E0080]: could not evaluate static initializer
--> $DIR/uninhabited-static.rs:12:31
|
LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 0, align: 1) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type

error[E0080]: it is undefined behavior to use this value
--> $DIR/uninhabited-static.rs:16:1
error[E0080]: could not evaluate static initializer
--> $DIR/uninhabited-static.rs:16:32
|
LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 0, align: 1) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type

warning: the type `Void` does not permit zero-initialization
--> $DIR/uninhabited-static.rs:12:31
Expand Down
29 changes: 29 additions & 0 deletions src/test/ui/uninhabited/privately-uninhabited-mir-call.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Verifies that MIR building for a call expression respects
// privacy when checking if a call return type is uninhabited.

pub mod widget {
enum Unimplemented {}
pub struct Widget(Unimplemented);

impl Widget {
pub fn new() -> Widget {
todo!();
}
}

pub fn f() {
let x: &mut u32;
Widget::new();
// Ok. Widget type returned from new is known to be uninhabited
// and the following code is considered unreachable.
*x = 1;
}
}

fn main() {
let y: &mut u32;
widget::Widget::new();
// Error. Widget type is not known to be uninhabited here,
// so the following code is considered reachable.
*y = 2; //~ ERROR use of possibly-uninitialized variable
}
Loading