From f11e40a8119bac1ab28c1cbaf18078466d84d951 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Fri, 16 Jun 2017 22:59:20 +0300 Subject: [PATCH] deriv(Hash) for single-variant enum should not hash discriminant Fixes #39137 --- src/libsyntax_ext/deriving/clone.rs | 2 +- src/libsyntax_ext/deriving/debug.rs | 2 +- src/libsyntax_ext/deriving/encodable.rs | 2 +- src/libsyntax_ext/deriving/generic/mod.rs | 9 +++++---- src/libsyntax_ext/deriving/hash.rs | 2 +- src/test/run-pass/deriving-hash.rs | 13 +++++++++++-- 6 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index 1993d6ebe5b49..35a2a2513f4e2 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -167,7 +167,7 @@ fn cs_clone(name: &str, all_fields = af; vdata = vdata_; } - EnumMatching(_, variant, ref af) => { + EnumMatching(.., variant, ref af) => { ctor_path = cx.path(trait_span, vec![substr.type_ident, variant.node.name]); all_fields = af; vdata = &variant.node.data; diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index ec4cb815960d1..38ed596098b21 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -60,7 +60,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P (substr.type_ident, vdata.is_struct()), - EnumMatching(_, v, _) => (v.node.name, v.node.data.is_struct()), + EnumMatching(_, _, v, _) => (v.node.name, v.node.data.is_struct()), EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`"), diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index 9d155c22ad031..811135e5368e6 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -233,7 +233,7 @@ fn encodable_substructure(cx: &mut ExtCtxt, blk]) } - EnumMatching(idx, variant, ref fields) => { + EnumMatching(idx, _, variant, ref fields) => { // We're not generating an AST that the borrow checker is expecting, // so we need to generate a unique local variable to take the // mutable loan out on, otherwise we get conflicts which don't diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index be7883cad5f38..1fe26a0ac4bb4 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -305,10 +305,10 @@ pub enum StaticFields { /// A summary of the possible sets of fields. pub enum SubstructureFields<'a> { Struct(&'a ast::VariantData, Vec>), - /// Matching variants of the enum: variant index, ast::Variant, + /// Matching variants of the enum: variant index, variant count, ast::Variant, /// fields: the field name is only non-`None` in the case of a struct /// variant. - EnumMatching(usize, &'a ast::Variant, Vec>), + EnumMatching(usize, usize, &'a ast::Variant, Vec>), /// Non-matching variants of the enum, but with all state hidden from /// the consequent code. The first component holds `Ident`s for all of @@ -1250,7 +1250,7 @@ impl<'a> MethodDef<'a> { // expressions for referencing every field of every // Self arg, assuming all are instances of VariantK. // Build up code associated with such a case. - let substructure = EnumMatching(index, variant, field_tuples); + let substructure = EnumMatching(index, variants.len(), variant, field_tuples); let arm_expr = self.call_substructure_method(cx, trait_, type_ident, @@ -1267,12 +1267,13 @@ impl<'a> MethodDef<'a> { // We need a default case that handles the fieldless variants. // The index and actual variant aren't meaningful in this case, // so just use whatever + let substructure = EnumMatching(0, variants.len(), v, Vec::new()); Some(self.call_substructure_method(cx, trait_, type_ident, &self_args[..], nonself_args, - &EnumMatching(0, v, Vec::new()))) + &substructure)) } _ if variants.len() > 1 && self_args.len() > 1 => { // Since we know that all the arguments will match if we reach diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index 97d7f2ce8003e..a341c21d0a126 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -81,7 +81,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) let mut stmts = Vec::new(); let fields = match *substr.fields { - Struct(_, ref fs) => fs, + Struct(_, ref fs) | EnumMatching(_, 1, .., ref fs) => fs, EnumMatching(.., ref fs) => { let variant_value = deriving::call_intrinsic(cx, trait_span, diff --git a/src/test/run-pass/deriving-hash.rs b/src/test/run-pass/deriving-hash.rs index 91bfc2f9201b7..18b2fbe015b42 100644 --- a/src/test/run-pass/deriving-hash.rs +++ b/src/test/run-pass/deriving-hash.rs @@ -45,8 +45,8 @@ impl<'a> Hasher for FakeHasher<'a> { } } -fn fake_hash(v: &mut Vec, e: E) { - e.hash(&mut FakeHasher(v)); +fn fake_hash(v: &mut Vec, a: A) { + a.hash(&mut FakeHasher(v)); } fn main() { @@ -69,4 +69,13 @@ fn main() { fake_hash(&mut va, E::A); fake_hash(&mut vb, E::B); assert!(va != vb); + + // issue #39137: single variant enum hash should not hash discriminant + #[derive(Hash)] + enum SingleVariantEnum { + A(u8), + } + let mut v = vec![]; + fake_hash(&mut v, SingleVariantEnum::A(17)); + assert_eq!(vec![17], v); }