Skip to content

Commit 23acd82

Browse files
authored
Rollup merge of rust-lang#92744 - lambinoo:I-91161-non-exhaustive-foreign-variants, r=scottmcm
Check if enum from foreign crate has any non exhaustive variants when attempting a cast Fixes rust-lang#91161 As stated in the issue, this will require a crater run as it might break other people's stuff.
2 parents 1876544 + dfb3713 commit 23acd82

File tree

3 files changed

+34
-8
lines changed

3 files changed

+34
-8
lines changed

compiler/rustc_typeck/src/check/cast.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use super::FnCtxt;
3232

3333
use crate::hir::def_id::DefId;
3434
use crate::type_error_struct;
35+
use hir::def_id::LOCAL_CRATE;
3536
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
3637
use rustc_hir as hir;
3738
use rustc_hir::lang_items::LangItem;
@@ -40,7 +41,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase;
4041
use rustc_middle::ty::cast::{CastKind, CastTy};
4142
use rustc_middle::ty::error::TypeError;
4243
use rustc_middle::ty::subst::SubstsRef;
43-
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable};
44+
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
4445
use rustc_session::lint;
4546
use rustc_session::Session;
4647
use rustc_span::symbol::sym;
@@ -173,6 +174,7 @@ pub enum CastError {
173174
/// or "a length". If this argument is None, then the metadata is unknown, for example,
174175
/// when we're typechecking a type parameter with a ?Sized bound.
175176
IntToFatCast(Option<&'static str>),
177+
ForeignNonExhaustiveAdt,
176178
}
177179

178180
impl From<ErrorGuaranteed> for CastError {
@@ -591,6 +593,17 @@ impl<'a, 'tcx> CastCheck<'tcx> {
591593
}
592594
err.emit();
593595
}
596+
CastError::ForeignNonExhaustiveAdt => {
597+
make_invalid_casting_error(
598+
fcx.tcx.sess,
599+
self.span,
600+
self.expr_ty,
601+
self.cast_ty,
602+
fcx,
603+
)
604+
.note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate")
605+
.emit();
606+
}
594607
}
595608
}
596609

@@ -789,6 +802,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
789802
_ => return Err(CastError::NonScalar),
790803
};
791804

805+
if let ty::Adt(adt_def, _) = *self.expr_ty.kind() {
806+
if adt_def.did().krate != LOCAL_CRATE {
807+
if adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) {
808+
return Err(CastError::ForeignNonExhaustiveAdt);
809+
}
810+
}
811+
}
812+
792813
match (t_from, t_cast) {
793814
// These types have invariants! can't cast into them.
794815
(_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar),
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
// aux-build:enums.rs
2-
// run-pass
32

43
extern crate enums;
54

65
use enums::FieldLessWithNonExhaustiveVariant;
76

87
fn main() {
98
let e = FieldLessWithNonExhaustiveVariant::default();
10-
// FIXME: https://github.com/rust-lang/rust/issues/91161
11-
// This `as` cast *should* be an error, since it would fail
12-
// if the non-exhaustive variant got fields. But today it
13-
// doesn't. The fix for that will update this test to
14-
// show an error (and not be run-pass any more).
15-
let d = e as u8;
9+
let d = e as u8; //~ ERROR casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid [E0606]
1610
assert_eq!(d, 0);
1711
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0606]: casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid
2+
--> $DIR/enum-as-cast.rs:9:13
3+
|
4+
LL | let d = e as u8;
5+
| ^^^^^^^
6+
|
7+
= note: cannot cast an enum with a non-exhaustive variant when it's defined in another crate
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0606`.

0 commit comments

Comments
 (0)