Check if extern crate enum has non exhaustive variant when cast
This commit is contained in:
parent
1603a70f82
commit
a3b84ad197
@ -32,6 +32,7 @@ use super::FnCtxt;
|
||||
|
||||
use crate::hir::def_id::DefId;
|
||||
use crate::type_error_struct;
|
||||
use hir::def_id::LOCAL_CRATE;
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
@ -40,7 +41,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
use rustc_middle::ty::cast::{CastKind, CastTy};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable};
|
||||
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
@ -173,6 +174,7 @@ pub enum CastError {
|
||||
/// or "a length". If this argument is None, then the metadata is unknown, for example,
|
||||
/// when we're typechecking a type parameter with a ?Sized bound.
|
||||
IntToFatCast(Option<&'static str>),
|
||||
ForeignNonExhaustiveAdt,
|
||||
}
|
||||
|
||||
impl From<ErrorGuaranteed> for CastError {
|
||||
@ -591,6 +593,17 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
CastError::ForeignNonExhaustiveAdt => {
|
||||
make_invalid_casting_error(
|
||||
fcx.tcx.sess,
|
||||
self.span,
|
||||
self.expr_ty,
|
||||
self.cast_ty,
|
||||
fcx,
|
||||
)
|
||||
.note("cannot cast a non-exhaustive enum defined in another crate")
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -789,6 +802,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
_ => return Err(CastError::NonScalar),
|
||||
};
|
||||
|
||||
if let ty::Adt(adt_def, _) = *self.expr_ty.kind() {
|
||||
if adt_def.did().krate != LOCAL_CRATE {
|
||||
if adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) {
|
||||
return Err(CastError::ForeignNonExhaustiveAdt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match (t_from, t_cast) {
|
||||
// These types have invariants! can't cast into them.
|
||||
(_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar),
|
||||
|
@ -1,5 +1,4 @@
|
||||
// aux-build:enums.rs
|
||||
// run-pass
|
||||
|
||||
extern crate enums;
|
||||
|
||||
@ -7,11 +6,6 @@ use enums::FieldLessWithNonExhaustiveVariant;
|
||||
|
||||
fn main() {
|
||||
let e = FieldLessWithNonExhaustiveVariant::default();
|
||||
// FIXME: https://github.com/rust-lang/rust/issues/91161
|
||||
// This `as` cast *should* be an error, since it would fail
|
||||
// if the non-exhaustive variant got fields. But today it
|
||||
// doesn't. The fix for that will update this test to
|
||||
// show an error (and not be run-pass any more).
|
||||
let d = e as u8;
|
||||
let d = e as u8; //~ ERROR casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid [E0606]
|
||||
assert_eq!(d, 0);
|
||||
}
|
||||
|
11
src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr
Normal file
11
src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr
Normal file
@ -0,0 +1,11 @@
|
||||
error[E0606]: casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid
|
||||
--> $DIR/enum-as-cast.rs:9:13
|
||||
|
|
||||
LL | let d = e as u8;
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: cannot cast a non-exhaustive enum defined in another crate
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0606`.
|
Loading…
x
Reference in New Issue
Block a user