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

Properly convert and translate unit structs into MIR #30551

Merged
merged 1 commit into from
Dec 25, 2015
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
4 changes: 2 additions & 2 deletions src/librustc/mir/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,9 +701,9 @@ pub struct Constant<'tcx> {
#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum ItemKind {
Constant,
/// This is any sort of callable (usually those that have a type of `fn(…) -> …`). This
/// includes functions, constructors, but not methods which have their own ItemKind.
Function,
Struct,
Variant,
Method,
}

Expand Down
58 changes: 29 additions & 29 deletions src/librustc_mir/hair/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -519,51 +519,51 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
// Otherwise there may be def_map borrow conflicts
let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
match def {
def::DefVariant(_, def_id, false) |
def::DefStruct(def_id) |
def::DefFn(def_id, _) |
def::DefMethod(def_id) => {
let kind = match def {
def::DefVariant(..) => ItemKind::Variant,
def::DefStruct(..) => ItemKind::Struct,
def::DefFn(..) => ItemKind::Function,
def::DefMethod(..) => ItemKind::Method,
_ => panic!()
};
ExprKind::Literal {
literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
let (def_id, kind) = match def {
// A variant constructor.
def::DefVariant(_, def_id, false) => (def_id, ItemKind::Function),
// A regular function.
def::DefFn(def_id, _) => (def_id, ItemKind::Function),
def::DefMethod(def_id) => (def_id, ItemKind::Method),
def::DefStruct(def_id) => {
match cx.tcx.node_id_to_type(expr.id).sty {
// A tuple-struct constructor.
ty::TyBareFn(..) => (def_id, ItemKind::Function),
// This is a special case: a unit struct which is used as a value. We return a
// completely different ExprKind here to account for this special case.
ty::TyStruct(adt_def, substs) => return ExprKind::Adt {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't you have the same problem with unit variants (e.g. Option::None)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, I now feel kinda stupid not having noticed it myself 😃.

adt_def: adt_def,
variant_index: 0,
substs: substs,
fields: vec![],
base: None
},
ref sty => panic!("unexpected sty: {:?}", sty)
}
},
def::DefConst(def_id) |
def::DefAssociatedConst(def_id) => {
if let Some(v) = cx.try_const_eval_literal(expr) {
ExprKind::Literal { literal: v }
return ExprKind::Literal { literal: v };
} else {
ExprKind::Literal {
literal: Literal::Item {
def_id: def_id,
kind: ItemKind::Constant,
substs: substs
}
}
(def_id, ItemKind::Constant)
}
}


def::DefStatic(node_id, _) =>
ExprKind::StaticRef {
id: node_id,
},
def::DefStatic(node_id, _) => return ExprKind::StaticRef {
id: node_id,
},

def @ def::DefLocal(..) |
def @ def::DefUpvar(..) =>
convert_var(cx, expr, def),
def @ def::DefUpvar(..) => return convert_var(cx, expr, def),

def =>
cx.tcx.sess.span_bug(
expr.span,
&format!("def `{:?}` not yet implemented", def)),
};
ExprKind::Literal {
literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
}
}

Expand Down
4 changes: 1 addition & 3 deletions src/librustc_trans/trans/mir/did.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
did: DefId)
-> OperandRef<'tcx> {
match kind {
ItemKind::Function |
ItemKind::Struct |
ItemKind::Variant => self.trans_fn_ref(bcx, ty, substs, did),
ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did),
ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did),
ty::TraitContainer(tdid) => self.trans_static_method(bcx, ty, did, tdid, substs)
Expand Down
49 changes: 31 additions & 18 deletions src/librustc_trans/trans/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,30 @@ use trans::common::{self, Block, Result};
use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::expr;
use trans::adt;
use trans::machine;
use trans::type_::Type;
use trans::type_of;
use trans::tvec;

use super::MirContext;
use super::operand::{OperandRef, OperandValue};
use super::lvalue::LvalueRef;

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
pub fn trans_rvalue(&mut self,
bcx: Block<'bcx, 'tcx>,
lldest: ValueRef,
dest: LvalueRef<'tcx>,
rvalue: &mir::Rvalue<'tcx>)
-> Block<'bcx, 'tcx>
{
debug!("trans_rvalue(lldest={}, rvalue={:?})",
bcx.val_to_string(lldest),
debug!("trans_rvalue(dest.llval={}, rvalue={:?})",
bcx.val_to_string(dest.llval),
rvalue);

match *rvalue {
mir::Rvalue::Use(ref operand) => {
self.trans_operand_into(bcx, lldest, operand);
self.trans_operand_into(bcx, dest.llval, operand);
bcx
}

Expand All @@ -49,7 +51,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
// into-coerce of a thin pointer to a fat pointer - just
// use the operand path.
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
self.store_operand(bcx, lldest, temp);
self.store_operand(bcx, dest.llval, temp);
return bcx;
}

Expand All @@ -72,12 +74,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
base::store_ty(bcx, llval, lltemp, operand.ty);
base::coerce_unsized_into(bcx,
lltemp, operand.ty,
lldest, cast_ty);
dest.llval, cast_ty);
}
OperandValue::Ref(llref) => {
base::coerce_unsized_into(bcx,
llref, operand.ty,
lldest, cast_ty);
dest.llval, cast_ty);
}
}
bcx
Expand All @@ -86,20 +88,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
mir::Rvalue::Repeat(ref elem, ref count) => {
let elem = self.trans_operand(bcx, elem);
let size = self.trans_constant(bcx, count).immediate();
let base = expr::get_dataptr(bcx, lldest);
let base = expr::get_dataptr(bcx, dest.llval);
tvec::iter_vec_raw(bcx, base, elem.ty, size, |bcx, llslot, _| {
self.store_operand(bcx, llslot, elem);
bcx
})
}

mir::Rvalue::Aggregate(_, ref operands) => {
for (i, operand) in operands.iter().enumerate() {
// Note: perhaps this should be StructGep, but
// note that in some cases the values here will
// not be structs but arrays.
let lldest_i = build::GEPi(bcx, lldest, &[0, i]);
self.trans_operand_into(bcx, lldest_i, operand);
mir::Rvalue::Aggregate(ref kind, ref operands) => {
match *kind {
// Unit struct, which is translated very differently compared to any other
// aggregate
mir::AggregateKind::Adt(adt_def, 0, _)
if adt_def.struct_variant().kind() == ty::VariantKind::Unit => {
let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx()));
adt::trans_set_discr(bcx, &*repr, dest.llval, 0);
},
_ => {
for (i, operand) in operands.iter().enumerate() {
// Note: perhaps this should be StructGep, but
// note that in some cases the values here will
// not be structs but arrays.
let lldest_i = build::GEPi(bcx, dest.llval, &[0, i]);
self.trans_operand_into(bcx, lldest_i, operand);
}
}
}
bcx
}
Expand All @@ -113,9 +126,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let llbase1 = build::GEPi(bcx, llbase, &[from_start]);
let adj = common::C_uint(ccx, from_start + from_end);
let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None);
let lladdrdest = expr::get_dataptr(bcx, lldest);
let lladdrdest = expr::get_dataptr(bcx, dest.llval);
build::Store(bcx, llbase1, lladdrdest);
let llmetadest = expr::get_meta(bcx, lldest);
let llmetadest = expr::get_meta(bcx, dest.llval);
build::Store(bcx, lllen1, llmetadest);
bcx
}
Expand All @@ -127,7 +140,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
_ => {
assert!(rvalue_creates_operand(rvalue));
let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue);
self.store_operand(bcx, lldest, temp);
self.store_operand(bcx, dest.llval, temp);
bcx
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_trans/trans/mir/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
let index = index as usize;
match self.temps[index as usize] {
TempRef::Lvalue(tr_dest) => {
self.trans_rvalue(bcx, tr_dest.llval, rvalue)
self.trans_rvalue(bcx, tr_dest, rvalue)
}
TempRef::Operand(None) => {
let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue);
Expand All @@ -47,7 +47,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
_ => {
let tr_dest = self.trans_lvalue(bcx, lvalue);
self.trans_rvalue(bcx, tr_dest.llval, rvalue)
self.trans_rvalue(bcx, tr_dest, rvalue)
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/test/run-pass/mir_refs_correct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
extern crate mir_external_refs as ext;

struct S(u8);
#[derive(Debug, PartialEq, Eq)]
struct Unit;

impl S {
fn hey() -> u8 { 42 }
Expand Down Expand Up @@ -175,6 +177,11 @@ fn t20() -> fn(u64, u32)->(u64, u32) {
<u32 as T<_, _>>::staticmeth
}

#[rustc_mir]
fn t21() -> Unit {
Unit
}

fn main(){
unsafe {
assert_eq!(t1()(), regular());
Expand Down Expand Up @@ -214,5 +221,6 @@ fn main(){
assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64));
assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32));
assert_eq!(t20()(123u64, 38u32), <u32 as T<_, _>>::staticmeth(123, 38));
assert_eq!(t21(), Unit);
}
}