diff --git a/src/rustc/middle/trans/datum.rs b/src/rustc/middle/trans/datum.rs index 5e11cdd4794..700ac402a8a 100644 --- a/src/rustc/middle/trans/datum.rs +++ b/src/rustc/middle/trans/datum.rs @@ -651,6 +651,41 @@ impl Datum { } }; } + ty::ty_class(did, ref substs) => { + // Check whether this struct is a newtype struct. + let fields = ty::class_items_as_fields(ccx.tcx, did, substs); + if fields.len() != 1 || fields[0].ident != + syntax::parse::token::special_idents::unnamed_field { + return None; + } + + let ty = fields[0].mt.ty; + return match self.mode { + ByRef => { + // Recast lv.val as a pointer to the newtype rather + // than a pointer to the struct type. + // XXX: This isn't correct for structs with + // destructors. + Some(Datum { + val: GEPi(bcx, self.val, [0, 0, 0]), + ty: ty, + mode: ByRef, + source: FromLvalue + }) + } + ByValue => { + // Actually, this case cannot happen right now, + // because structs are never immediate. But in + // principle, newtype'd immediate values should be + // immediate, and in that case the * would be a no-op + // except for changing the type, so I am putting this + // code in place here to do the right thing if this + // change ever goes through. + assert ty::type_is_immediate(ty); + Some(Datum {ty: ty, ..self}) + } + } + } _ => { // not derefable. return None; } diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 8767c4c6253..4391388331c 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -2597,6 +2597,16 @@ fn deref_sty(cx: ctxt, sty: &sty, expl: bool) -> Option { } } + ty_class(did, ref substs) => { + let fields = class_items_as_fields(cx, did, substs); + if fields.len() == 1 && fields[0].ident == + syntax::parse::token::special_idents::unnamed_field { + Some({ty: fields[0].mt.ty, mutbl: ast::m_imm}) + } else { + None + } + } + _ => None } } diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index b29e85643f1..8a74a8ed48b 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -1768,6 +1768,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, with a single variant which has a \ single argument"); } + ty::ty_class(*) => { + tcx.sess.span_err( + expr.span, + ~"can only dereference structs with one anonymous \ + field"); + } _ => { tcx.sess.span_err( expr.span, diff --git a/src/test/run-pass/struct-deref.rs b/src/test/run-pass/struct-deref.rs new file mode 100644 index 00000000000..74726f3c867 --- /dev/null +++ b/src/test/run-pass/struct-deref.rs @@ -0,0 +1,7 @@ +struct Foo(int); + +fn main() { + let x: Foo = Foo(2); + assert *x == 2; +} +