Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

derive: use discriminant_value in #[derive(Hash)] #32252

Merged
merged 5 commits into from
Mar 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mk/crates.mk
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
test rustc_lint rustc_front


TOOL_DEPS_compiletest := test getopts
TOOL_DEPS_compiletest := test getopts log
TOOL_DEPS_rustdoc := rustdoc
TOOL_DEPS_rustc := rustc_driver
TOOL_DEPS_rustbook := std rustdoc
Expand Down
2 changes: 1 addition & 1 deletion mk/main.mk
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ endif
LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3) := \
$$(CURDIR)/$$(HLIB$(1)_H_$(3)):$$(CFG_LLVM_INST_DIR_$(3))/lib
LD_LIBRARY_PATH_ENV_TARGETDIR$(1)_T_$(2)_H_$(3) := \
$$(CURDIR)/$$(TLIB1_T_$(2)_H_$(CFG_BUILD))
$$(CURDIR)/$$(TLIB$(1)_T_$(2)_H_$(CFG_BUILD))

HOST_RPATH_VAR$(1)_T_$(2)_H_$(3) := \
$$(LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3))=$$(LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3)):$$$$$$(LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3))
Expand Down
38 changes: 11 additions & 27 deletions src/libsyntax_ext/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ use syntax::ptr::P;

use self::ty::{LifetimeBounds, Path, Ptr, PtrTy, Self_, Ty};

use deriving;

pub mod ty;

pub struct TraitDef<'a> {
Expand Down Expand Up @@ -381,22 +383,6 @@ fn find_type_parameters(ty: &ast::Ty, ty_param_names: &[ast::Name]) -> Vec<P<ast
visitor.types
}

/// Replacement for expr_unreachable which generates intrinsics::unreachable()
/// instead of unreachable!()
fn expr_unreachable_intrinsic(cx: &ExtCtxt, sp: Span) -> P<Expr> {
let path = cx.std_path(&["intrinsics", "unreachable"]);
let call = cx.expr_call_global(
sp, path, vec![]);
let unreachable = cx.expr_block(P(ast::Block {
stmts: vec![],
expr: Some(call),
id: ast::DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
span: sp }));

unreachable
}

impl<'a> TraitDef<'a> {
pub fn expand(&self,
cx: &mut ExtCtxt,
Expand Down Expand Up @@ -1279,15 +1265,11 @@ impl<'a> MethodDef<'a> {

let mut first_ident = None;
for (&ident, self_arg) in vi_idents.iter().zip(&self_args) {
let path = cx.std_path(&["intrinsics", "discriminant_value"]);
let call = cx.expr_call_global(
sp, path, vec![cx.expr_addr_of(sp, self_arg.clone())]);
let variant_value = cx.expr_block(P(ast::Block {
stmts: vec![],
expr: Some(call),
id: ast::DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
span: sp }));
let self_addr = cx.expr_addr_of(sp, self_arg.clone());
let variant_value = deriving::call_intrinsic(cx,
sp,
"discriminant_value",
vec![self_addr]);

let target_ty = cx.ty_ident(sp, cx.ident_of(target_type_name));
let variant_disr = cx.expr_cast(sp, variant_value, target_ty);
Expand Down Expand Up @@ -1315,7 +1297,9 @@ impl<'a> MethodDef<'a> {
//Since we know that all the arguments will match if we reach the match expression we
//add the unreachable intrinsics as the result of the catch all which should help llvm
//in optimizing it
match_arms.push(cx.arm(sp, vec![cx.pat_wild(sp)], expr_unreachable_intrinsic(cx, sp)));
match_arms.push(cx.arm(sp,
vec![cx.pat_wild(sp)],
deriving::call_intrinsic(cx, sp, "unreachable", vec![])));

// Final wrinkle: the self_args are expressions that deref
// down to desired l-values, but we cannot actually deref
Expand Down Expand Up @@ -1391,7 +1375,7 @@ impl<'a> MethodDef<'a> {
// derive Debug on such a type could here generate code
// that needs the feature gate enabled.)

expr_unreachable_intrinsic(cx, sp)
deriving::call_intrinsic(cx, sp, "unreachable", vec![])
}
else {

Expand Down
14 changes: 6 additions & 8 deletions src/libsyntax_ext/deriving/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,13 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)

let fields = match *substr.fields {
Struct(_, ref fs) => fs,
EnumMatching(index, variant, ref fs) => {
// Determine the discriminant. We will feed this value to the byte
// iteration function.
let discriminant = match variant.node.disr_expr {
Some(ref d) => d.clone(),
None => cx.expr_usize(trait_span, index)
};
EnumMatching(_, _, ref fs) => {
let variant_value = deriving::call_intrinsic(cx,
trait_span,
"discriminant_value",
vec![cx.expr_self(trait_span)]);

stmts.push(call_hash(trait_span, discriminant));
stmts.push(call_hash(trait_span, variant_value));

fs
}
Expand Down
17 changes: 17 additions & 0 deletions src/libsyntax_ext/deriving/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use syntax::ext::build::AstBuilder;
use syntax::feature_gate;
use syntax::codemap::Span;
use syntax::parse::token::{intern, intern_and_get_ident};
use syntax::ptr::P;

macro_rules! pathvec {
($($x:ident)::+) => (
Expand Down Expand Up @@ -271,3 +272,19 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String {
typaram
}

/// Constructs an expression that calls an intrinsic
fn call_intrinsic(cx: &ExtCtxt,
span: Span,
intrinsic: &str,
args: Vec<P<ast::Expr>>) -> P<ast::Expr> {
let path = cx.std_path(&["intrinsics", intrinsic]);
let call = cx.expr_call_global(span, path, args);

cx.expr_block(P(ast::Block {
stmts: vec![],
expr: Some(call),
id: ast::DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated),
span: span }))
}

26 changes: 26 additions & 0 deletions src/test/run-pass/deriving-hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#![feature(hash_default)]

use std::hash::{Hash, SipHasher, Hasher};
use std::mem::size_of;

#[derive(Hash)]
struct Person {
Expand All @@ -24,12 +25,30 @@ struct Person {
#[derive(Hash)] struct __H__H;
#[derive(Hash)] enum Collision<__H> { __H { __H__H: __H } }

#[derive(Hash)]
enum E { A=1, B }

fn hash<T: Hash>(t: &T) -> u64 {
let mut s = SipHasher::new_with_keys(0, 0);
t.hash(&mut s);
s.finish()
}

struct FakeHasher<'a>(&'a mut Vec<u8>);
impl<'a> Hasher for FakeHasher<'a> {
fn finish(&self) -> u64 {
unimplemented!()
}

fn write(&mut self, bytes: &[u8]) {
self.0.extend(bytes);
}
}

fn fake_hash(v: &mut Vec<u8>, e: E) {
e.hash(&mut FakeHasher(v));
}

fn main() {
let person1 = Person {
id: 5,
Expand All @@ -43,4 +62,11 @@ fn main() {
};
assert_eq!(hash(&person1), hash(&person1));
assert!(hash(&person1) != hash(&person2));

// test #21714
let mut va = vec![];
let mut vb = vec![];
fake_hash(&mut va, E::A);
fake_hash(&mut vb, E::B);
assert!(va != vb);
}