rustc: Implement dereference via unary '*' for structs. r=nmatsakis

This commit is contained in:
Patrick Walton 2012-10-30 18:31:47 -07:00
parent 4165edff22
commit 65d4dbeb12
4 changed files with 58 additions and 0 deletions

View File

@ -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;
}

View File

@ -2597,6 +2597,16 @@ fn deref_sty(cx: ctxt, sty: &sty, expl: bool) -> Option<mt> {
}
}
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
}
}

View File

@ -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,

View File

@ -0,0 +1,7 @@
struct Foo(int);
fn main() {
let x: Foo = Foo(2);
assert *x == 2;
}