Skip to content

Commit 8c89601

Browse files
authored
Rollup merge of #111494 - compiler-errors:variant-order, r=petrochenkov
Encode `VariantIdx` so we can decode ADT variants in the right order As far as I can tell, we don't guarantee anything about the ordering of `DefId`s and module children... The code that motivated this PR (#111483) looks something like: ```rust #[derive(Protocol)] pub enum Data { #[protocol(discriminator(0x00))] Disconnect(Disconnect), EncryptionRequest, /* more variants... */ } ``` The specific macro ([`protocol`](https://github.com/dylanmckay/protocol)) doesn't really matter, but as far as I can tell (from calls to `build_reduced_graph`), the presence of that `#[protocol(..)]` helper attribute causes the def-id of the `Disconnect` enum variant to be collected *after* its siblings, and it shows up after the other variants in `module_children`. When we decode the variants for `Data` in a child crate (an example test, in this case), this means that the `Disconnect` variant is moved to the end of the variants list, and all of the other variants now have incorrect relative discriminant data, causing the ICE. This PR fixes this by sorting manually by variant index after they are decoded. I guess there are alternative ways of fixing this, such as not reusing `module_children_non_reexports` to encode the order-sensitive ADT variants, or to do some sorting in `rustc_resolve`... but none of those seemed particularly satisfying either. ~I really struggled to create a reproduction here -- it required at least 3 crates, one of which is a proc macro, and then some code to actually compute discriminants in the child crate... Needless to say, I failed to repro this in a test, but I can confirm that it fixes the regression in #111483.~ Test exists now. r? `@petrochenkov` but feel free to reassign. ~Again, sorry for no test, but I hope the explanation at least suggests why a fix like this is likely necessary.~ Feedback is welcome.
2 parents 770fd73 + ff54c80 commit 8c89601

File tree

5 files changed

+58
-22
lines changed

5 files changed

+58
-22
lines changed

compiler/rustc_metadata/src/rmeta/decoder.rs

+36-21
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
856856
ty::EarlyBinder(&*output)
857857
}
858858

859-
fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef {
859+
fn get_variant(
860+
self,
861+
kind: DefKind,
862+
index: DefIndex,
863+
parent_did: DefId,
864+
) -> (VariantIdx, ty::VariantDef) {
860865
let adt_kind = match kind {
861866
DefKind::Variant => ty::AdtKind::Enum,
862867
DefKind::Struct => ty::AdtKind::Struct,
@@ -870,22 +875,25 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
870875
if adt_kind == ty::AdtKind::Enum { Some(self.local_def_id(index)) } else { None };
871876
let ctor = data.ctor.map(|(kind, index)| (kind, self.local_def_id(index)));
872877

873-
ty::VariantDef::new(
874-
self.item_name(index),
875-
variant_did,
876-
ctor,
877-
data.discr,
878-
self.get_associated_item_or_field_def_ids(index)
879-
.map(|did| ty::FieldDef {
880-
did,
881-
name: self.item_name(did.index),
882-
vis: self.get_visibility(did.index),
883-
})
884-
.collect(),
885-
adt_kind,
886-
parent_did,
887-
false,
888-
data.is_non_exhaustive,
878+
(
879+
data.idx,
880+
ty::VariantDef::new(
881+
self.item_name(index),
882+
variant_did,
883+
ctor,
884+
data.discr,
885+
self.get_associated_item_or_field_def_ids(index)
886+
.map(|did| ty::FieldDef {
887+
did,
888+
name: self.item_name(did.index),
889+
vis: self.get_visibility(did.index),
890+
})
891+
.collect(),
892+
adt_kind,
893+
parent_did,
894+
false,
895+
data.is_non_exhaustive,
896+
),
889897
)
890898
}
891899

@@ -901,7 +909,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
901909
};
902910
let repr = self.root.tables.repr_options.get(self, item_id).unwrap().decode(self);
903911

904-
let variants = if let ty::AdtKind::Enum = adt_kind {
912+
let mut variants: Vec<_> = if let ty::AdtKind::Enum = adt_kind {
905913
self.root
906914
.tables
907915
.module_children_non_reexports
@@ -912,15 +920,22 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
912920
let kind = self.def_kind(index);
913921
match kind {
914922
DefKind::Ctor(..) => None,
915-
_ => Some(self.get_variant(&kind, index, did)),
923+
_ => Some(self.get_variant(kind, index, did)),
916924
}
917925
})
918926
.collect()
919927
} else {
920-
std::iter::once(self.get_variant(&kind, item_id, did)).collect()
928+
std::iter::once(self.get_variant(kind, item_id, did)).collect()
921929
};
922930

923-
tcx.mk_adt_def(did, adt_kind, variants, repr)
931+
variants.sort_by_key(|(idx, _)| *idx);
932+
933+
tcx.mk_adt_def(
934+
did,
935+
adt_kind,
936+
variants.into_iter().map(|(_, variant)| variant).collect(),
937+
repr,
938+
)
924939
}
925940

926941
fn get_visibility(self, id: DefIndex) -> Visibility<DefId> {

compiler/rustc_metadata/src/rmeta/encoder.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1375,9 +1375,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
13751375
// Therefore, the loop over variants will encode its fields as the adt's children.
13761376
}
13771377

1378-
for variant in adt_def.variants().iter() {
1378+
for (idx, variant) in adt_def.variants().iter_enumerated() {
13791379
let data = VariantData {
13801380
discr: variant.discr,
1381+
idx,
13811382
ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
13821383
is_non_exhaustive: variant.is_field_list_non_exhaustive(),
13831384
};

compiler/rustc_metadata/src/rmeta/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use rustc_span::edition::Edition;
3131
use rustc_span::hygiene::{ExpnIndex, MacroKind};
3232
use rustc_span::symbol::{Ident, Symbol};
3333
use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span};
34+
use rustc_target::abi::VariantIdx;
3435
use rustc_target::spec::{PanicStrategy, TargetTriple};
3536

3637
use std::marker::PhantomData;
@@ -430,6 +431,7 @@ define_tables! {
430431

431432
#[derive(TyEncodable, TyDecodable)]
432433
struct VariantData {
434+
idx: VariantIdx,
433435
discr: ty::VariantDiscr,
434436
/// If this is unit or tuple-variant/struct, then this is the index of the ctor id.
435437
ctor: Option<(CtorKind, DefIndex)>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#[derive(Default)]
2+
pub enum Foo {
3+
A(u32),
4+
#[default]
5+
B,
6+
C(u32),
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// aux-build:discr-foreign-dep.rs
2+
// build-pass
3+
4+
extern crate discr_foreign_dep;
5+
6+
fn main() {
7+
match Default::default() {
8+
discr_foreign_dep::Foo::A(_) => {}
9+
_ => {}
10+
}
11+
}

0 commit comments

Comments
 (0)