about summary refs log tree commit diff
path: root/compiler/rustc_passes
diff options
context:
space:
mode:
authorGeorge Bateman <george.bateman16@gmail.com>2023-08-15 20:10:45 +0100
committerGeorge Bateman <george.bateman16@gmail.com>2023-10-31 23:25:54 +0000
commite936416a8d3cfb501504f00d7250d5b595fed244 (patch)
treec0dd8196372db8a77ae1a90d38d87b630658e90e /compiler/rustc_passes
parent9d83ac217957eece2189eccf4a7232caec7232ee (diff)
downloadrust-e936416a8d3cfb501504f00d7250d5b595fed244.tar.gz
rust-e936416a8d3cfb501504f00d7250d5b595fed244.zip
Support enum variants in offset_of!
Diffstat (limited to 'compiler/rustc_passes')
-rw-r--r--compiler/rustc_passes/src/dead.rs29
1 files changed, 22 insertions, 7 deletions
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 87d4850b475..3b4f6a618c8 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -248,6 +248,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
     }
 
     fn handle_offset_of(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+        use rustc_target::abi::OffsetOfIdx::*;
+
         let data = self.typeck_results().offset_of_data();
         let &(container, ref indices) =
             data.get(expr.hir_id).expect("no offset_of_data for offset_of");
@@ -256,11 +258,23 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         let param_env = self.tcx.param_env(body_did);
 
         let mut current_ty = container;
+        let mut indices = indices.into_iter();
+
+        while let Some(&index) = indices.next() {
+            match (current_ty.kind(), index) {
+                (ty::Adt(def, subst), Field(field)) if !def.is_enum() => {
+                    let field = &def.non_enum_variant().fields[field];
 
-        for &index in indices {
-            match current_ty.kind() {
-                ty::Adt(def, subst) => {
-                    let field = &def.non_enum_variant().fields[index];
+                    self.insert_def_id(field.did);
+                    let field_ty = field.ty(self.tcx, subst);
+
+                    current_ty = self.tcx.normalize_erasing_regions(param_env, field_ty);
+                }
+                (ty::Adt(def, subst), Variant(variant)) if def.is_enum() => {
+                    let Some(&Field(field)) = indices.next() else {
+                        span_bug!(expr.span, "variant must be followed by field in offset_of")
+                    };
+                    let field = &def.variant(variant).fields[field];
 
                     self.insert_def_id(field.did);
                     let field_ty = field.ty(self.tcx, subst);
@@ -269,11 +283,12 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
                 }
                 // we don't need to mark tuple fields as live,
                 // but we may need to mark subfields
-                ty::Tuple(tys) => {
+                (ty::Tuple(tys), Field(field)) => {
                     current_ty =
-                        self.tcx.normalize_erasing_regions(param_env, tys[index.as_usize()]);
+                        self.tcx.normalize_erasing_regions(param_env, tys[field.as_usize()]);
                 }
-                _ => span_bug!(expr.span, "named field access on non-ADT"),
+                (_, Field(_)) => span_bug!(expr.span, "named field access on non-ADT"),
+                (_, Variant(_)) => span_bug!(expr.span, "enum variant access on non-enum"),
             }
         }
     }