Skip to content

Commit f11e40a

Browse files
committed
deriv(Hash) for single-variant enum should not hash discriminant
Fixes #39137
1 parent b40be00 commit f11e40a

File tree

6 files changed

+20
-10
lines changed

6 files changed

+20
-10
lines changed

src/libsyntax_ext/deriving/clone.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ fn cs_clone(name: &str,
167167
all_fields = af;
168168
vdata = vdata_;
169169
}
170-
EnumMatching(_, variant, ref af) => {
170+
EnumMatching(.., variant, ref af) => {
171171
ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.name]);
172172
all_fields = af;
173173
vdata = &variant.node.data;

src/libsyntax_ext/deriving/debug.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P<E
6060
// based on the "shape".
6161
let (ident, is_struct) = match *substr.fields {
6262
Struct(vdata, _) => (substr.type_ident, vdata.is_struct()),
63-
EnumMatching(_, v, _) => (v.node.name, v.node.data.is_struct()),
63+
EnumMatching(_, _, v, _) => (v.node.name, v.node.data.is_struct()),
6464
EnumNonMatchingCollapsed(..) |
6565
StaticStruct(..) |
6666
StaticEnum(..) => cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"),

src/libsyntax_ext/deriving/encodable.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ fn encodable_substructure(cx: &mut ExtCtxt,
233233
blk])
234234
}
235235

236-
EnumMatching(idx, variant, ref fields) => {
236+
EnumMatching(idx, _, variant, ref fields) => {
237237
// We're not generating an AST that the borrow checker is expecting,
238238
// so we need to generate a unique local variable to take the
239239
// mutable loan out on, otherwise we get conflicts which don't

src/libsyntax_ext/deriving/generic/mod.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,10 @@ pub enum StaticFields {
305305
/// A summary of the possible sets of fields.
306306
pub enum SubstructureFields<'a> {
307307
Struct(&'a ast::VariantData, Vec<FieldInfo<'a>>),
308-
/// Matching variants of the enum: variant index, ast::Variant,
308+
/// Matching variants of the enum: variant index, variant count, ast::Variant,
309309
/// fields: the field name is only non-`None` in the case of a struct
310310
/// variant.
311-
EnumMatching(usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
311+
EnumMatching(usize, usize, &'a ast::Variant, Vec<FieldInfo<'a>>),
312312

313313
/// Non-matching variants of the enum, but with all state hidden from
314314
/// the consequent code. The first component holds `Ident`s for all of
@@ -1250,7 +1250,7 @@ impl<'a> MethodDef<'a> {
12501250
// expressions for referencing every field of every
12511251
// Self arg, assuming all are instances of VariantK.
12521252
// Build up code associated with such a case.
1253-
let substructure = EnumMatching(index, variant, field_tuples);
1253+
let substructure = EnumMatching(index, variants.len(), variant, field_tuples);
12541254
let arm_expr = self.call_substructure_method(cx,
12551255
trait_,
12561256
type_ident,
@@ -1267,12 +1267,13 @@ impl<'a> MethodDef<'a> {
12671267
// We need a default case that handles the fieldless variants.
12681268
// The index and actual variant aren't meaningful in this case,
12691269
// so just use whatever
1270+
let substructure = EnumMatching(0, variants.len(), v, Vec::new());
12701271
Some(self.call_substructure_method(cx,
12711272
trait_,
12721273
type_ident,
12731274
&self_args[..],
12741275
nonself_args,
1275-
&EnumMatching(0, v, Vec::new())))
1276+
&substructure))
12761277
}
12771278
_ if variants.len() > 1 && self_args.len() > 1 => {
12781279
// Since we know that all the arguments will match if we reach

src/libsyntax_ext/deriving/hash.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
8181
let mut stmts = Vec::new();
8282

8383
let fields = match *substr.fields {
84-
Struct(_, ref fs) => fs,
84+
Struct(_, ref fs) | EnumMatching(_, 1, .., ref fs) => fs,
8585
EnumMatching(.., ref fs) => {
8686
let variant_value = deriving::call_intrinsic(cx,
8787
trait_span,

src/test/run-pass/deriving-hash.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ impl<'a> Hasher for FakeHasher<'a> {
4545
}
4646
}
4747

48-
fn fake_hash(v: &mut Vec<u8>, e: E) {
49-
e.hash(&mut FakeHasher(v));
48+
fn fake_hash<A: Hash>(v: &mut Vec<u8>, a: A) {
49+
a.hash(&mut FakeHasher(v));
5050
}
5151

5252
fn main() {
@@ -69,4 +69,13 @@ fn main() {
6969
fake_hash(&mut va, E::A);
7070
fake_hash(&mut vb, E::B);
7171
assert!(va != vb);
72+
73+
// issue #39137: single variant enum hash should not hash discriminant
74+
#[derive(Hash)]
75+
enum SingleVariantEnum {
76+
A(u8),
77+
}
78+
let mut v = vec![];
79+
fake_hash(&mut v, SingleVariantEnum::A(17));
80+
assert_eq!(vec![17], v);
7281
}

0 commit comments

Comments
 (0)