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.
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.
12 use rustc
::hir
::def_id
::DefId
;
14 use rustc
::middle
::const_val
::ConstVal
;
16 use rustc
::mir
::transform
::MirSource
;
17 use rustc
::ty
::{self, Ty}
;
18 use rustc
::ty
::subst
::{Kind, Subst, Substs}
;
19 use rustc
::ty
::maps
::Providers
;
21 use rustc_data_structures
::indexed_vec
::{IndexVec, Idx}
;
30 use transform
::{add_call_guards, no_landing_pads, simplify}
;
31 use util
::elaborate_drops
::{self, DropElaborator, DropStyle, DropFlagMode}
;
32 use util
::patch
::MirPatch
;
34 pub fn provide(providers
: &mut Providers
) {
35 providers
.mir_shims
= make_shim
;
38 fn make_shim
<'a
, 'tcx
>(tcx
: ty
::TyCtxt
<'a
, 'tcx
, 'tcx
>,
39 instance
: ty
::InstanceDef
<'tcx
>)
42 debug
!("make_shim({:?})", instance
);
44 let mut result
= match instance
{
45 ty
::InstanceDef
::Item(..) =>
46 bug
!("item {:?} passed to make_shim", instance
),
47 ty
::InstanceDef
::FnPtrShim(def_id
, ty
) => {
48 let trait_
= tcx
.trait_of_item(def_id
).unwrap();
49 let adjustment
= match tcx
.lang_items
.fn_trait_kind(trait_
) {
50 Some(ty
::ClosureKind
::FnOnce
) => Adjustment
::Identity
,
51 Some(ty
::ClosureKind
::FnMut
) |
52 Some(ty
::ClosureKind
::Fn
) => Adjustment
::Deref
,
53 None
=> bug
!("fn pointer {:?} is not an fn", ty
)
55 // HACK: we need the "real" argument types for the MIR,
56 // but because our substs are (Self, Args), where Args
57 // is a tuple, we must include the *concrete* argument
58 // types in the MIR. They will be substituted again with
59 // the param-substs, but because they are concrete, this
60 // will not do any harm.
61 let sig
= tcx
.erase_late_bound_regions(&ty
.fn_sig(tcx
));
62 let arg_tys
= sig
.inputs();
72 ty
::InstanceDef
::Virtual(def_id
, _
) => {
73 // We are translating a call back to our def-id, which
74 // trans::mir knows to turn to an actual virtual call.
79 CallKind
::Direct(def_id
),
83 ty
::InstanceDef
::ClosureOnceShim { call_once }
=> {
84 let fn_mut
= tcx
.lang_items
.fn_mut_trait().unwrap();
85 let call_mut
= tcx
.global_tcx()
86 .associated_items(fn_mut
)
87 .find(|it
| it
.kind
== ty
::AssociatedKind
::Method
)
94 CallKind
::Direct(call_mut
),
98 ty
::InstanceDef
::DropGlue(def_id
, ty
) => {
99 build_drop_shim(tcx
, def_id
, ty
)
101 ty
::InstanceDef
::Intrinsic(_
) => {
102 bug
!("creating shims from intrinsics ({:?}) is unsupported", instance
)
105 debug
!("make_shim({:?}) = untransformed {:?}", instance
, result
);
106 no_landing_pads
::no_landing_pads(tcx
, &mut result
);
107 simplify
::simplify_cfg(&mut result
);
108 add_call_guards
::add_call_guards(&mut result
);
109 debug
!("make_shim({:?}) = {:?}", instance
, result
);
111 tcx
.alloc_mir(result
)
114 #[derive(Copy, Clone, Debug, PartialEq)]
121 #[derive(Copy, Clone, Debug, PartialEq)]
127 fn temp_decl(mutability
: Mutability
, ty
: Ty
, span
: Span
) -> LocalDecl
{
129 mutability
, ty
, name
: None
,
130 source_info
: SourceInfo { scope: ARGUMENT_VISIBILITY_SCOPE, span }
,
131 is_user_variable
: false
135 fn local_decls_for_sig
<'tcx
>(sig
: &ty
::FnSig
<'tcx
>, span
: Span
)
136 -> IndexVec
<Local
, LocalDecl
<'tcx
>>
138 iter
::once(temp_decl(Mutability
::Mut
, sig
.output(), span
))
139 .chain(sig
.inputs().iter().map(
140 |ity
| temp_decl(Mutability
::Not
, ity
, span
)))
144 fn build_drop_shim
<'a
, 'tcx
>(tcx
: ty
::TyCtxt
<'a
, 'tcx
, 'tcx
>,
146 ty
: Option
<Ty
<'tcx
>>)
149 debug
!("build_drop_shim(def_id={:?}, ty={:?})", def_id
, ty
);
151 let substs
= if let Some(ty
) = ty
{
152 tcx
.mk_substs(iter
::once(Kind
::from(ty
)))
154 Substs
::identity_for_item(tcx
, def_id
)
156 let sig
= tcx
.fn_sig(def_id
).subst(tcx
, substs
);
157 let sig
= tcx
.erase_late_bound_regions(&sig
);
158 let span
= tcx
.def_span(def_id
);
160 let source_info
= SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }
;
162 let return_block
= BasicBlock
::new(1);
163 let mut blocks
= IndexVec
::new();
164 let block
= |blocks
: &mut IndexVec
<_
, _
>, kind
| {
165 blocks
.push(BasicBlockData
{
167 terminator
: Some(Terminator { source_info, kind }
),
171 block(&mut blocks
, TerminatorKind
::Goto { target: return_block }
);
172 block(&mut blocks
, TerminatorKind
::Return
);
174 let mut mir
= Mir
::new(
176 IndexVec
::from_elem_n(
177 VisibilityScopeData { span: span, parent_scope: None }
, 1
181 local_decls_for_sig(&sig
, span
),
187 if let Some(..) = ty
{
189 let param_env
= tcx
.param_env(def_id
);
190 let mut elaborator
= DropShimElaborator
{
192 patch
: MirPatch
::new(&mir
),
196 let dropee
= Lvalue
::Local(Local
::new(1+0)).deref();
197 let resume_block
= elaborator
.patch
.resume_block();
198 elaborate_drops
::elaborate_drop(
204 elaborate_drops
::Unwind
::To(resume_block
),
209 patch
.apply(&mut mir
);
215 pub struct DropShimElaborator
<'a
, 'tcx
: 'a
> {
217 patch
: MirPatch
<'tcx
>,
218 tcx
: ty
::TyCtxt
<'a
, 'tcx
, 'tcx
>,
219 param_env
: ty
::ParamEnv
<'tcx
>,
222 impl<'a
, 'tcx
> fmt
::Debug
for DropShimElaborator
<'a
, 'tcx
> {
223 fn fmt(&self, _f
: &mut fmt
::Formatter
) -> Result
<(), fmt
::Error
> {
228 impl<'a
, 'tcx
> DropElaborator
<'a
, 'tcx
> for DropShimElaborator
<'a
, 'tcx
> {
231 fn patch(&mut self) -> &mut MirPatch
<'tcx
> { &mut self.patch }
232 fn mir(&self) -> &'a Mir
<'tcx
> { self.mir }
233 fn tcx(&self) -> ty
::TyCtxt
<'a
, 'tcx
, 'tcx
> { self.tcx }
234 fn param_env(&self) -> ty
::ParamEnv
<'tcx
> { self.param_env }
236 fn drop_style(&self, _path
: Self::Path
, mode
: DropFlagMode
) -> DropStyle
{
237 if let DropFlagMode
::Shallow
= mode
{
244 fn get_drop_flag(&mut self, _path
: Self::Path
) -> Option
<Operand
<'tcx
>> {
248 fn clear_drop_flag(&mut self, _location
: Location
, _path
: Self::Path
, _mode
: DropFlagMode
) {
251 fn field_subpath(&self, _path
: Self::Path
, _field
: Field
) -> Option
<Self::Path
> {
254 fn deref_subpath(&self, _path
: Self::Path
) -> Option
<Self::Path
> {
257 fn downcast_subpath(&self, _path
: Self::Path
, _variant
: usize) -> Option
<Self::Path
> {
262 /// Build a "call" shim for `def_id`. The shim calls the
263 /// function specified by `call_kind`, first adjusting its first
264 /// argument according to `rcvr_adjustment`.
266 /// If `untuple_args` is a vec of types, the second argument of the
267 /// function will be untupled as these types.
268 fn build_call_shim
<'a
, 'tcx
>(tcx
: ty
::TyCtxt
<'a
, 'tcx
, 'tcx
>,
270 rcvr_adjustment
: Adjustment
,
272 untuple_args
: Option
<&[Ty
<'tcx
>]>)
275 debug
!("build_call_shim(def_id={:?}, rcvr_adjustment={:?}, \
276 call_kind={:?}, untuple_args={:?})",
277 def_id
, rcvr_adjustment
, call_kind
, untuple_args
);
279 let sig
= tcx
.fn_sig(def_id
);
280 let sig
= tcx
.erase_late_bound_regions(&sig
);
281 let span
= tcx
.def_span(def_id
);
283 debug
!("build_call_shim: sig={:?}", sig
);
285 let mut local_decls
= local_decls_for_sig(&sig
, span
);
286 let source_info
= SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }
;
288 let rcvr_arg
= Local
::new(1+0);
289 let rcvr_l
= Lvalue
::Local(rcvr_arg
);
290 let mut statements
= vec
![];
292 let rcvr
= match rcvr_adjustment
{
293 Adjustment
::Identity
=> Operand
::Consume(rcvr_l
),
294 Adjustment
::Deref
=> Operand
::Consume(rcvr_l
.deref()),
295 Adjustment
::RefMut
=> {
296 // let rcvr = &mut rcvr;
297 let ref_rcvr
= local_decls
.push(temp_decl(
299 tcx
.mk_ref(tcx
.types
.re_erased
, ty
::TypeAndMut
{
301 mutbl
: hir
::Mutability
::MutMutable
305 statements
.push(Statement
{
306 source_info
: source_info
,
307 kind
: StatementKind
::Assign(
308 Lvalue
::Local(ref_rcvr
),
309 Rvalue
::Ref(tcx
.types
.re_erased
, BorrowKind
::Mut
, rcvr_l
)
312 Operand
::Consume(Lvalue
::Local(ref_rcvr
))
316 let (callee
, mut args
) = match call_kind
{
317 CallKind
::Indirect
=> (rcvr
, vec
![]),
318 CallKind
::Direct(def_id
) => (
319 Operand
::Constant(box Constant
{
321 ty
: tcx
.type_of(def_id
),
322 literal
: Literal
::Value
{
323 value
: ConstVal
::Function(def_id
,
324 Substs
::identity_for_item(tcx
, def_id
)),
331 if let Some(untuple_args
) = untuple_args
{
332 args
.extend(untuple_args
.iter().enumerate().map(|(i
, ity
)| {
333 let arg_lv
= Lvalue
::Local(Local
::new(1+1));
334 Operand
::Consume(arg_lv
.field(Field
::new(i
), *ity
))
337 args
.extend((1..sig
.inputs().len()).map(|i
| {
338 Operand
::Consume(Lvalue
::Local(Local
::new(1+i
)))
342 let mut blocks
= IndexVec
::new();
343 let block
= |blocks
: &mut IndexVec
<_
, _
>, statements
, kind
, is_cleanup
| {
344 blocks
.push(BasicBlockData
{
346 terminator
: Some(Terminator { source_info, kind }
),
352 block(&mut blocks
, statements
, TerminatorKind
::Call
{
355 destination
: Some((Lvalue
::Local(RETURN_POINTER
),
356 BasicBlock
::new(1))),
357 cleanup
: if let Adjustment
::RefMut
= rcvr_adjustment
{
358 Some(BasicBlock
::new(3))
364 if let Adjustment
::RefMut
= rcvr_adjustment
{
365 // BB #1 - drop for Self
366 block(&mut blocks
, vec
![], TerminatorKind
::Drop
{
367 location
: Lvalue
::Local(rcvr_arg
),
368 target
: BasicBlock
::new(2),
373 block(&mut blocks
, vec
![], TerminatorKind
::Return
, false);
374 if let Adjustment
::RefMut
= rcvr_adjustment
{
375 // BB #3 - drop if closure panics
376 block(&mut blocks
, vec
![], TerminatorKind
::Drop
{
377 location
: Lvalue
::Local(rcvr_arg
),
378 target
: BasicBlock
::new(4),
383 block(&mut blocks
, vec
![], TerminatorKind
::Resume
, true);
386 let mut mir
= Mir
::new(
388 IndexVec
::from_elem_n(
389 VisibilityScopeData { span: span, parent_scope: None }
, 1
398 if let Abi
::RustCall
= sig
.abi
{
399 mir
.spread_arg
= Some(Local
::new(sig
.inputs().len()));
404 pub fn build_adt_ctor
<'a
, 'gcx
, 'tcx
>(infcx
: &infer
::InferCtxt
<'a
, 'gcx
, 'tcx
>,
405 ctor_id
: ast
::NodeId
,
406 fields
: &[hir
::StructField
],
408 -> (Mir
<'tcx
>, MirSource
)
411 let def_id
= tcx
.hir
.local_def_id(ctor_id
);
412 let sig
= tcx
.no_late_bound_regions(&tcx
.fn_sig(def_id
))
413 .expect("LBR in ADT constructor signature");
414 let sig
= tcx
.erase_regions(&sig
);
416 let (adt_def
, substs
) = match sig
.output().sty
{
417 ty
::TyAdt(adt_def
, substs
) => (adt_def
, substs
),
418 _
=> bug
!("unexpected type for ADT ctor {:?}", sig
.output())
421 debug
!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id
, sig
, fields
);
423 let local_decls
= local_decls_for_sig(&sig
, span
);
425 let source_info
= SourceInfo
{
427 scope
: ARGUMENT_VISIBILITY_SCOPE
430 let variant_no
= if adt_def
.is_enum() {
431 adt_def
.variant_index_with_id(def_id
)
436 // return = ADT(arg0, arg1, ...); return
437 let start_block
= BasicBlockData
{
438 statements
: vec
![Statement
{
439 source_info
: source_info
,
440 kind
: StatementKind
::Assign(
441 Lvalue
::Local(RETURN_POINTER
),
443 box AggregateKind
::Adt(adt_def
, variant_no
, substs
, None
),
444 (1..sig
.inputs().len()+1).map(|i
| {
445 Operand
::Consume(Lvalue
::Local(Local
::new(i
)))
450 terminator
: Some(Terminator
{
451 source_info
: source_info
,
452 kind
: TerminatorKind
::Return
,
458 IndexVec
::from_elem_n(start_block
, 1),
459 IndexVec
::from_elem_n(
460 VisibilityScopeData { span: span, parent_scope: None }
, 1
469 (mir
, MirSource
::Fn(ctor_id
))