Check if extern crate enum has non exhaustive variant when cast

This commit is contained in:
Lamb 2022-01-10 21:01:23 +00:00 committed by Scott McMurray
parent 1603a70f82
commit a3b84ad197
3 changed files with 34 additions and 8 deletions

View File

@ -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),

View File

@ -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);
}

View 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`.