Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 0af3775

Browse files
committed
translate tuple-variant constructors using MIR
1 parent a559452 commit 0af3775

File tree

11 files changed

+215
-138
lines changed

11 files changed

+215
-138
lines changed

src/librustc/ty/mod.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1264,10 +1264,17 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
12641264
def_id,
12651265
ROOT_CODE_EXTENT)
12661266
}
1267-
_ => {
1267+
Some(hir_map::NodeStructCtor(..)) |
1268+
Some(hir_map::NodeVariant(..)) => {
1269+
let def_id = tcx.hir.local_def_id(id);
1270+
tcx.construct_parameter_environment(tcx.hir.span(id),
1271+
def_id,
1272+
ROOT_CODE_EXTENT)
1273+
}
1274+
it => {
12681275
bug!("ParameterEnvironment::from_item(): \
1269-
`{}` is not an item",
1270-
tcx.hir.node_to_string(id))
1276+
`{}` = {:?} is unsupported",
1277+
tcx.hir.node_to_string(id), it)
12711278
}
12721279
}
12731280
}

src/librustc_metadata/encoder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
293293
predicates: Some(self.encode_predicates(def_id)),
294294

295295
ast: None,
296-
mir: None,
296+
mir: self.encode_mir(def_id),
297297
}
298298
}
299299

@@ -426,7 +426,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
426426
predicates: Some(self.encode_predicates(def_id)),
427427

428428
ast: None,
429-
mir: None,
429+
mir: self.encode_mir(def_id),
430430
}
431431
}
432432

src/librustc_mir/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
2222

2323
#![feature(associated_consts)]
2424
#![feature(box_patterns)]
25+
#![feature(box_syntax)]
2526
#![feature(i128_type)]
2627
#![feature(rustc_diagnostic_macros)]
2728
#![feature(rustc_private)]
@@ -50,6 +51,7 @@ pub mod callgraph;
5051
pub mod def_use;
5152
pub mod graphviz;
5253
mod hair;
54+
mod shim;
5355
pub mod mir_map;
5456
pub mod pretty;
5557
pub mod transform;

src/librustc_mir/mir_map.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use rustc::dep_graph::DepNode;
2222
use rustc::mir::Mir;
2323
use rustc::mir::transform::MirSource;
2424
use rustc::mir::visit::MutVisitor;
25+
use shim;
2526
use pretty;
2627
use hair::cx::Cx;
2728

@@ -30,6 +31,7 @@ use rustc::ty::{self, Ty, TyCtxt};
3031
use rustc::ty::maps::Providers;
3132
use rustc::ty::subst::Substs;
3233
use rustc::hir;
34+
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
3335
use syntax::abi::Abi;
3436
use syntax::ast;
3537
use syntax_pos::Span;
@@ -44,6 +46,31 @@ pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
4446
tcx.visit_all_bodies_in_krate(|body_owner_def_id, _body_id| {
4547
tcx.item_mir(body_owner_def_id);
4648
});
49+
50+
// Tuple struct/variant constructors don't have a BodyId, so we need
51+
// to build them separately.
52+
struct GatherCtors<'a, 'tcx: 'a> {
53+
tcx: TyCtxt<'a, 'tcx, 'tcx>
54+
}
55+
impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
56+
fn visit_variant_data(&mut self,
57+
v: &'tcx hir::VariantData,
58+
_: ast::Name,
59+
_: &'tcx hir::Generics,
60+
_: ast::NodeId,
61+
_: Span) {
62+
if let hir::VariantData::Tuple(_, node_id) = *v {
63+
self.tcx.item_mir(self.tcx.hir.local_def_id(node_id));
64+
}
65+
intravisit::walk_struct_def(self, v)
66+
}
67+
fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
68+
NestedVisitorMap::None
69+
}
70+
}
71+
tcx.visit_all_item_likes_in_krate(DepNode::Mir, &mut GatherCtors {
72+
tcx: tcx
73+
}.as_deep_visitor());
4774
}
4875
}
4976

@@ -95,6 +122,10 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
95122
_ => hir::BodyId { node_id: expr.id }
96123
}
97124
}
125+
hir::map::NodeVariant(variant) =>
126+
return create_constructor_shim(tcx, id, &variant.node.data),
127+
hir::map::NodeStructCtor(ctor) =>
128+
return create_constructor_shim(tcx, id, ctor),
98129
_ => unsupported()
99130
};
100131

@@ -180,6 +211,38 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
180211
}
181212
}
182213

214+
fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
215+
ctor_id: ast::NodeId,
216+
v: &'tcx hir::VariantData)
217+
-> &'tcx RefCell<Mir<'tcx>>
218+
{
219+
let span = tcx.hir.span(ctor_id);
220+
if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
221+
let pe = ty::ParameterEnvironment::for_item(tcx, ctor_id);
222+
tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| {
223+
let (mut mir, src) =
224+
shim::build_adt_ctor(&infcx, ctor_id, fields, span);
225+
226+
// Convert the Mir to global types.
227+
let tcx = infcx.tcx.global_tcx();
228+
let mut globalizer = GlobalizeMir {
229+
tcx: tcx,
230+
span: mir.span
231+
};
232+
globalizer.visit_mir(&mut mir);
233+
let mir = unsafe {
234+
mem::transmute::<Mir, Mir<'tcx>>(mir)
235+
};
236+
237+
pretty::dump_mir(tcx, "mir_map", &0, src, &mir);
238+
239+
tcx.alloc_mir(mir)
240+
})
241+
} else {
242+
span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v);
243+
}
244+
}
245+
183246
///////////////////////////////////////////////////////////////////////////
184247
// BuildMir -- walks a crate, looking for fn items and methods to build MIR from
185248

src/librustc_mir/shim.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use rustc::hir;
12+
use rustc::infer;
13+
use rustc::mir::*;
14+
use rustc::mir::transform::MirSource;
15+
use rustc::ty;
16+
17+
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
18+
19+
use syntax::ast;
20+
use syntax_pos::Span;
21+
22+
use std::iter;
23+
24+
fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>)
25+
-> IndexVec<Local, LocalDecl<'tcx>>
26+
{
27+
iter::once(LocalDecl {
28+
mutability: Mutability::Mut,
29+
ty: sig.output(),
30+
name: None,
31+
source_info: None
32+
}).chain(sig.inputs().iter().map(|ity| LocalDecl {
33+
mutability: Mutability::Not,
34+
ty: *ity,
35+
name: None,
36+
source_info: None,
37+
})).collect()
38+
}
39+
40+
pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
41+
ctor_id: ast::NodeId,
42+
fields: &[hir::StructField],
43+
span: Span)
44+
-> (Mir<'tcx>, MirSource)
45+
{
46+
let tcx = infcx.tcx;
47+
let def_id = tcx.hir.local_def_id(ctor_id);
48+
let sig = match tcx.item_type(def_id).sty {
49+
ty::TyFnDef(_, _, fty) => tcx.no_late_bound_regions(&fty)
50+
.expect("LBR in ADT constructor signature"),
51+
_ => bug!("unexpected type for ctor {:?}", def_id)
52+
};
53+
let sig = tcx.erase_regions(&sig);
54+
55+
let (adt_def, substs) = match sig.output().sty {
56+
ty::TyAdt(adt_def, substs) => (adt_def, substs),
57+
_ => bug!("unexpected type for ADT ctor {:?}", sig.output())
58+
};
59+
60+
debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields);
61+
62+
let local_decls = local_decls_for_sig(&sig);
63+
64+
let source_info = SourceInfo {
65+
span: span,
66+
scope: ARGUMENT_VISIBILITY_SCOPE
67+
};
68+
69+
let variant_no = if adt_def.is_enum() {
70+
adt_def.variant_index_with_id(def_id)
71+
} else {
72+
0
73+
};
74+
75+
// return = ADT(arg0, arg1, ...); return
76+
let start_block = BasicBlockData {
77+
statements: vec![Statement {
78+
source_info: source_info,
79+
kind: StatementKind::Assign(
80+
Lvalue::Local(RETURN_POINTER),
81+
Rvalue::Aggregate(
82+
AggregateKind::Adt(adt_def, variant_no, substs, None),
83+
(1..sig.inputs().len()+1).map(|i| {
84+
Operand::Consume(Lvalue::Local(Local::new(i)))
85+
}).collect()
86+
)
87+
)
88+
}],
89+
terminator: Some(Terminator {
90+
source_info: source_info,
91+
kind: TerminatorKind::Return,
92+
}),
93+
is_cleanup: false
94+
};
95+
96+
let mir = Mir::new(
97+
IndexVec::from_elem_n(start_block, 1),
98+
IndexVec::from_elem_n(
99+
VisibilityScopeData { span: span, parent_scope: None }, 1
100+
),
101+
IndexVec::new(),
102+
sig.output(),
103+
local_decls,
104+
sig.inputs().len(),
105+
vec![],
106+
span
107+
);
108+
(mir, MirSource::Fn(ctor_id))
109+
}

src/librustc_trans/base.rs

Lines changed: 4 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,8 @@ use back::linker::LinkerInfo;
3434
use back::symbol_export::{self, ExportedSymbols};
3535
use llvm::{Linkage, ValueRef, Vector, get_param};
3636
use llvm;
37-
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
37+
use rustc::hir::def_id::LOCAL_CRATE;
3838
use middle::lang_items::StartFnLangItem;
39-
use rustc::ty::subst::Substs;
40-
use rustc::mir::tcx::LvalueTy;
4139
use rustc::traits;
4240
use rustc::ty::{self, Ty, TyCtxt};
4341
use rustc::ty::adjustment::CustomCoerceUnsized;
@@ -47,9 +45,8 @@ use rustc::util::common::time;
4745
use session::config::{self, NoDebugInfo};
4846
use rustc_incremental::IncrementalHashesMap;
4947
use session::{self, DataTypeKind, Session};
50-
use abi::{self, FnType};
48+
use abi;
5149
use mir::lvalue::LvalueRef;
52-
use adt;
5350
use attributes;
5451
use builder::Builder;
5552
use callee::{Callee};
@@ -65,7 +62,7 @@ use context::{SharedCrateContext, CrateContextList};
6562
use debuginfo;
6663
use declare;
6764
use machine;
68-
use machine::{llalign_of_min, llsize_of};
65+
use machine::llsize_of;
6966
use meth;
7067
use mir;
7168
use monomorphize::{self, Instance};
@@ -76,7 +73,6 @@ use trans_item::{TransItem, DefPathBasedNames};
7673
use type_::Type;
7774
use type_of;
7875
use value::Value;
79-
use Disr;
8076
use util::nodemap::{NodeSet, FxHashMap, FxHashSet};
8177

8278
use libc::c_uint;
@@ -615,72 +611,6 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
615611
mir::trans_mir(ccx, lldecl, &mir, instance, sig);
616612
}
617613

618-
pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
619-
def_id: DefId,
620-
substs: &'tcx Substs<'tcx>,
621-
disr: Disr,
622-
llfn: ValueRef) {
623-
attributes::inline(llfn, attributes::InlineAttr::Hint);
624-
attributes::set_frame_pointer_elimination(ccx, llfn);
625-
626-
let ctor_ty = common::def_ty(ccx.shared(), def_id, substs);
627-
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig());
628-
let fn_ty = FnType::new(ccx, sig, &[]);
629-
630-
let bcx = Builder::new_block(ccx, llfn, "entry-block");
631-
if !fn_ty.ret.is_ignore() {
632-
// But if there are no nested returns, we skip the indirection
633-
// and have a single retslot
634-
let dest = if fn_ty.ret.is_indirect() {
635-
get_param(llfn, 0)
636-
} else {
637-
// We create an alloca to hold a pointer of type `ret.original_ty`
638-
// which will hold the pointer to the right alloca which has the
639-
// final ret value
640-
bcx.alloca(fn_ty.ret.memory_ty(ccx), "sret_slot")
641-
};
642-
// Can return unsized value
643-
let mut dest_val = LvalueRef::new_sized_ty(dest, sig.output(), Alignment::AbiAligned);
644-
dest_val.ty = LvalueTy::Downcast {
645-
adt_def: sig.output().ty_adt_def().unwrap(),
646-
substs: substs,
647-
variant_index: disr.0 as usize,
648-
};
649-
let mut llarg_idx = fn_ty.ret.is_indirect() as usize;
650-
let mut arg_idx = 0;
651-
for (i, arg_ty) in sig.inputs().iter().enumerate() {
652-
let (lldestptr, _) = dest_val.trans_field_ptr(&bcx, i);
653-
let arg = &fn_ty.args[arg_idx];
654-
arg_idx += 1;
655-
if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
656-
let meta = &fn_ty.args[arg_idx];
657-
arg_idx += 1;
658-
arg.store_fn_arg(&bcx, &mut llarg_idx, get_dataptr(&bcx, lldestptr));
659-
meta.store_fn_arg(&bcx, &mut llarg_idx, get_meta(&bcx, lldestptr));
660-
} else {
661-
arg.store_fn_arg(&bcx, &mut llarg_idx, lldestptr);
662-
}
663-
}
664-
adt::trans_set_discr(&bcx, sig.output(), dest, disr);
665-
666-
if fn_ty.ret.is_indirect() {
667-
bcx.ret_void();
668-
return;
669-
}
670-
671-
if let Some(cast_ty) = fn_ty.ret.cast {
672-
bcx.ret(bcx.load(
673-
bcx.pointercast(dest, cast_ty.ptr_to()),
674-
Some(llalign_of_min(ccx, fn_ty.ret.ty))
675-
));
676-
} else {
677-
bcx.ret(bcx.load(dest, None))
678-
}
679-
} else {
680-
bcx.ret_void();
681-
}
682-
}
683-
684614
pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
685615
// Use the names from src/llvm/docs/LangRef.rst here. Most types are only
686616
// applicable to variable declarations and may not really make sense for
@@ -721,7 +651,7 @@ pub fn set_link_section(ccx: &CrateContext,
721651
}
722652

723653
/// Create the `main` function which will initialise the rust runtime and call
724-
/// users main function.
654+
/// users main function.
725655
pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
726656
let (main_def_id, span) = match *ccx.sess().entry_fn.borrow() {
727657
Some((id, span)) => {

0 commit comments

Comments
 (0)