Skip to content

Commit

Permalink
Rollup merge of #92744 - lambinoo:I-91161-non-exhaustive-foreign-vari…
Browse files Browse the repository at this point in the history
…ants, r=scottmcm

Check if enum from foreign crate has any non exhaustive variants when attempting a cast

Fixes #91161

As stated in the issue, this will require a crater run as it might break other people's stuff.
  • Loading branch information
Dylan-DPC authored Aug 11, 2022
2 parents aeb5067 + dfb3713 commit dfddc2f
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 8 deletions.
23 changes: 22 additions & 1 deletion compiler/rustc_typeck/src/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 an enum with a non-exhaustive variant when it's defined in another crate")
.emit();
}
}
}

Expand Down Expand Up @@ -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),
Expand Down
8 changes: 1 addition & 7 deletions src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
// aux-build:enums.rs
// run-pass

extern crate enums;

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 changes: 11 additions & 0 deletions src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr
Original file line number Diff line number Diff line change
@@ -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 an enum with a non-exhaustive variant when it's defined in another crate

error: aborting due to previous error

For more information about this error, try `rustc --explain E0606`.

0 comments on commit dfddc2f

Please sign in to comment.