Skip to content

Commit 65d4dbe

Browse files
committed
rustc: Implement dereference via unary '*' for structs. r=nmatsakis
1 parent 4165edf commit 65d4dbe

File tree

4 files changed

+58
-0
lines changed

4 files changed

+58
-0
lines changed

src/rustc/middle/trans/datum.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,41 @@ impl Datum {
651651
}
652652
};
653653
}
654+
ty::ty_class(did, ref substs) => {
655+
// Check whether this struct is a newtype struct.
656+
let fields = ty::class_items_as_fields(ccx.tcx, did, substs);
657+
if fields.len() != 1 || fields[0].ident !=
658+
syntax::parse::token::special_idents::unnamed_field {
659+
return None;
660+
}
661+
662+
let ty = fields[0].mt.ty;
663+
return match self.mode {
664+
ByRef => {
665+
// Recast lv.val as a pointer to the newtype rather
666+
// than a pointer to the struct type.
667+
// XXX: This isn't correct for structs with
668+
// destructors.
669+
Some(Datum {
670+
val: GEPi(bcx, self.val, [0, 0, 0]),
671+
ty: ty,
672+
mode: ByRef,
673+
source: FromLvalue
674+
})
675+
}
676+
ByValue => {
677+
// Actually, this case cannot happen right now,
678+
// because structs are never immediate. But in
679+
// principle, newtype'd immediate values should be
680+
// immediate, and in that case the * would be a no-op
681+
// except for changing the type, so I am putting this
682+
// code in place here to do the right thing if this
683+
// change ever goes through.
684+
assert ty::type_is_immediate(ty);
685+
Some(Datum {ty: ty, ..self})
686+
}
687+
}
688+
}
654689
_ => { // not derefable.
655690
return None;
656691
}

src/rustc/middle/ty.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2597,6 +2597,16 @@ fn deref_sty(cx: ctxt, sty: &sty, expl: bool) -> Option<mt> {
25972597
}
25982598
}
25992599
2600+
ty_class(did, ref substs) => {
2601+
let fields = class_items_as_fields(cx, did, substs);
2602+
if fields.len() == 1 && fields[0].ident ==
2603+
syntax::parse::token::special_idents::unnamed_field {
2604+
Some({ty: fields[0].mt.ty, mutbl: ast::m_imm})
2605+
} else {
2606+
None
2607+
}
2608+
}
2609+
26002610
_ => None
26012611
}
26022612
}

src/rustc/middle/typeck/check.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1768,6 +1768,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
17681768
with a single variant which has a \
17691769
single argument");
17701770
}
1771+
ty::ty_class(*) => {
1772+
tcx.sess.span_err(
1773+
expr.span,
1774+
~"can only dereference structs with one anonymous \
1775+
field");
1776+
}
17711777
_ => {
17721778
tcx.sess.span_err(
17731779
expr.span,

src/test/run-pass/struct-deref.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
struct Foo(int);
2+
3+
fn main() {
4+
let x: Foo = Foo(2);
5+
assert *x == 2;
6+
}
7+

0 commit comments

Comments
 (0)