about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs23
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs8
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr11
3 files changed, 34 insertions, 8 deletions
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 7aaddc2bd7a..88bce06297b 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -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),
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs
index d9657bac776..5dce8180f59 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs
@@ -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);
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr
new file mode 100644
index 00000000000..c5f0105296f
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr
@@ -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`.