Skip to content

Commit c85284e

Browse files
authored
Rollup merge of rust-lang#67054 - RalfJung:set-discriminant-unreachable, r=oli-obk
codegen "unreachable" for invalid SetDiscriminant Follow-up from rust-lang#66960. I also realized I don't understand our policy for using `abort` vs `unreachable`. AFAIK `abort` is safe to call and just aborts the process, while `unreachable` is UB. But sometimes we use both, like here https://github.com/rust-lang/rust/blob/d825e35ee8325146e6c175a4c61bcb645b347d5e/src/librustc_codegen_ssa/mir/block.rs#L827-L828 and here https://github.com/rust-lang/rust/blob/d825e35ee8325146e6c175a4c61bcb645b347d5e/src/librustc_codegen_ssa/mir/block.rs#L264-L265 The second case is even more confusing because that looks like an unreachable `return` to me, so why would we codegen a safe abort there? r? @eddyb Cc @oli-obk
2 parents d1397db + f5bd947 commit c85284e

File tree

4 files changed

+59
-4
lines changed

4 files changed

+59
-4
lines changed

src/librustc_codegen_ssa/mir/block.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
261261
if self.fn_abi.ret.layout.abi.is_uninhabited() {
262262
// Functions with uninhabited return values are marked `noreturn`,
263263
// so we should make sure that we never actually do.
264+
// We play it safe by using a well-defined `abort`, but we could go for immediate UB
265+
// if that turns out to be helpful.
264266
bx.abort();
267+
// `abort` does not terminate the block, so we still need to generate
268+
// an `unreachable` terminator after it.
265269
bx.unreachable();
266270
return;
267271
}
@@ -825,6 +829,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
825829

826830
mir::TerminatorKind::Abort => {
827831
bx.abort();
832+
// `abort` does not terminate the block, so we still need to generate
833+
// an `unreachable` terminator after it.
828834
bx.unreachable();
829835
}
830836

src/librustc_codegen_ssa/mir/operand.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -475,9 +475,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
475475
},
476476
}
477477
// Allow RalfJ to sleep soundly knowing that even refactorings that remove
478-
// the above error (or silence it under some conditions) will not cause UB
478+
// the above error (or silence it under some conditions) will not cause UB.
479479
bx.abort();
480-
// We've errored, so we don't have to produce working code.
480+
// We still have to return an operand but it doesn't matter,
481+
// this code is unreachable.
481482
let ty = self.monomorphize(&constant.literal.ty);
482483
let layout = bx.cx().layout_of(ty);
483484
bx.load_operand(PlaceRef::new_sized(

src/librustc_codegen_ssa/mir/place.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
333333
variant_index: VariantIdx
334334
) {
335335
if self.layout.for_variant(bx.cx(), variant_index).abi.is_uninhabited() {
336+
// We play it safe by using a well-defined `abort`, but we could go for immediate UB
337+
// if that turns out to be helpful.
338+
bx.abort();
336339
return;
337340
}
338341
match self.layout.variants {
@@ -488,10 +491,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
488491
},
489492
Err(_) => {
490493
// This is unreachable as long as runtime
491-
// and compile-time agree on values
494+
// and compile-time agree perfectly.
492495
// With floats that won't always be true,
493-
// so we generate an abort.
496+
// so we generate a (safe) abort.
494497
bx.abort();
498+
// We still have to return a place but it doesn't matter,
499+
// this code is unreachable.
495500
let llval = bx.cx().const_undef(
496501
bx.cx().type_ptr_to(bx.cx().backend_type(layout))
497502
);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// compile-flags: -C opt-level=0
2+
#![crate_type = "lib"]
3+
4+
pub enum ApiError {}
5+
#[allow(dead_code)]
6+
pub struct TokioError {
7+
b: bool,
8+
}
9+
pub enum Error {
10+
Api {
11+
source: ApiError,
12+
},
13+
Ethereum,
14+
Tokio {
15+
source: TokioError,
16+
},
17+
}
18+
struct Api;
19+
impl IntoError<Error> for Api
20+
{
21+
type Source = ApiError;
22+
// CHECK-LABEL: @into_error
23+
// CHECK: llvm.trap()
24+
// Also check the next two instructions to make sure we do not match against `trap`
25+
// elsewhere in the code.
26+
// CHECK-NEXT: load
27+
// CHECK-NEXT: ret
28+
#[no_mangle]
29+
fn into_error(self, error: Self::Source) -> Error {
30+
Error::Api {
31+
source: (|v| v)(error),
32+
}
33+
}
34+
}
35+
36+
pub trait IntoError<E>
37+
{
38+
/// The underlying error
39+
type Source;
40+
41+
/// Combine the information to produce the error
42+
fn into_error(self, source: Self::Source) -> E;
43+
}

0 commit comments

Comments
 (0)