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
::region
::ROOT_CODE_EXTENT
;
15 use rustc
::middle
::const_val
::ConstVal
;
17 use rustc
::mir
::transform
::MirSource
;
18 use rustc
::ty
::{self, Ty}
;
19 use rustc
::ty
::subst
::{Kind, Subst}
;
20 use rustc
::ty
::maps
::Providers
;
22 use rustc_data_structures
::indexed_vec
::{IndexVec, Idx}
;
28 use std
::cell
::RefCell
;
33 use transform
::{add_call_guards, no_landing_pads, simplify}
;
34 use util
::elaborate_drops
::{self, DropElaborator, DropStyle, DropFlagMode}
;
35 use util
::patch
::MirPatch
;
37 pub fn provide(providers
: &mut Providers
) {
38 providers
.mir_shims
= make_shim
;
41 fn make_shim
<'a
, 'tcx
>(tcx
: ty
::TyCtxt
<'a
, 'tcx
, 'tcx
>,
42 instance
: ty
::InstanceDef
<'tcx
>)
43 -> &'tcx RefCell
<Mir
<'tcx
>>
45 debug
!("make_shim({:?})", instance
);
46 let did
= instance
.def_id();
47 let span
= tcx
.def_span(did
);
49 tcx
.construct_parameter_environment(span
, did
, ROOT_CODE_EXTENT
);
51 let mut result
= match instance
{
52 ty
::InstanceDef
::Item(..) =>
53 bug
!("item {:?} passed to make_shim", instance
),
54 ty
::InstanceDef
::FnPtrShim(def_id
, ty
) => {
55 let trait_
= tcx
.trait_of_item(def_id
).unwrap();
56 let adjustment
= match tcx
.lang_items
.fn_trait_kind(trait_
) {
57 Some(ty
::ClosureKind
::FnOnce
) => Adjustment
::Identity
,
58 Some(ty
::ClosureKind
::FnMut
) |
59 Some(ty
::ClosureKind
::Fn
) => Adjustment
::Deref
,
60 None
=> bug
!("fn pointer {:?} is not an fn", ty
)
62 // HACK: we need the "real" argument types for the MIR,
63 // but because our substs are (Self, Args), where Args
64 // is a tuple, we must include the *concrete* argument
65 // types in the MIR. They will be substituted again with
66 // the param-substs, but because they are concrete, this
67 // will not do any harm.
68 let sig
= tcx
.erase_late_bound_regions(&ty
.fn_sig());
69 let arg_tys
= sig
.inputs();
80 ty
::InstanceDef
::Virtual(def_id
, _
) => {
81 // We are translating a call back to our def-id, which
82 // trans::mir knows to turn to an actual virtual call.
88 CallKind
::Direct(def_id
),
92 ty
::InstanceDef
::ClosureOnceShim { call_once }
=> {
93 let fn_mut
= tcx
.lang_items
.fn_mut_trait().unwrap();
94 let call_mut
= tcx
.global_tcx()
95 .associated_items(fn_mut
)
96 .find(|it
| it
.kind
== ty
::AssociatedKind
::Method
)
104 CallKind
::Direct(call_mut
),
108 ty
::InstanceDef
::DropGlue(def_id
, ty
) => {
109 build_drop_shim(tcx
, ¶m_env
, def_id
, ty
)
111 ty
::InstanceDef
::Intrinsic(_
) => {
112 bug
!("creating shims from intrinsics ({:?}) is unsupported", instance
)
115 debug
!("make_shim({:?}) = untransformed {:?}", instance
, result
);
116 no_landing_pads
::no_landing_pads(tcx
, &mut result
);
117 simplify
::simplify_cfg(&mut result
);
118 add_call_guards
::add_call_guards(&mut result
);
119 debug
!("make_shim({:?}) = {:?}", instance
, result
);
121 let result
= tcx
.alloc_mir(result
);
122 // Perma-borrow MIR from shims to prevent mutation.
123 mem
::forget(result
.borrow());
127 #[derive(Copy, Clone, Debug, PartialEq)]
134 #[derive(Copy, Clone, Debug, PartialEq)]
140 fn temp_decl(mutability
: Mutability
, ty
: Ty
, span
: Span
) -> LocalDecl
{
142 mutability
, ty
, name
: None
,
143 source_info
: SourceInfo { scope: ARGUMENT_VISIBILITY_SCOPE, span }
,
144 is_user_variable
: false
148 fn local_decls_for_sig
<'tcx
>(sig
: &ty
::FnSig
<'tcx
>, span
: Span
)
149 -> IndexVec
<Local
, LocalDecl
<'tcx
>>
151 iter
::once(temp_decl(Mutability
::Mut
, sig
.output(), span
))
152 .chain(sig
.inputs().iter().map(
153 |ity
| temp_decl(Mutability
::Not
, ity
, span
)))
157 fn build_drop_shim
<'a
, 'tcx
>(tcx
: ty
::TyCtxt
<'a
, 'tcx
, 'tcx
>,
158 param_env
: &ty
::ParameterEnvironment
<'tcx
>,
160 ty
: Option
<Ty
<'tcx
>>)
163 debug
!("build_drop_shim(def_id={:?}, ty={:?})", def_id
, ty
);
165 let substs
= if let Some(ty
) = ty
{
166 tcx
.mk_substs(iter
::once(Kind
::from(ty
)))
168 param_env
.free_substs
170 let fn_ty
= tcx
.item_type(def_id
).subst(tcx
, substs
);
171 let sig
= tcx
.erase_late_bound_regions(&fn_ty
.fn_sig());
172 let span
= tcx
.def_span(def_id
);
174 let source_info
= SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }
;
176 let return_block
= BasicBlock
::new(1);
177 let mut blocks
= IndexVec
::new();
178 let block
= |blocks
: &mut IndexVec
<_
, _
>, kind
| {
179 blocks
.push(BasicBlockData
{
181 terminator
: Some(Terminator { source_info, kind }
),
185 block(&mut blocks
, TerminatorKind
::Goto { target: return_block }
);
186 block(&mut blocks
, TerminatorKind
::Return
);
188 let mut mir
= Mir
::new(
190 IndexVec
::from_elem_n(
191 VisibilityScopeData { span: span, parent_scope: None }
, 1
195 local_decls_for_sig(&sig
, span
),
201 if let Some(..) = ty
{
203 let mut elaborator
= DropShimElaborator
{
205 patch
: MirPatch
::new(&mir
),
208 let dropee
= Lvalue
::Local(Local
::new(1+0)).deref();
209 let resume_block
= elaborator
.patch
.resume_block();
210 elaborate_drops
::elaborate_drop(
222 patch
.apply(&mut mir
);
228 pub struct DropShimElaborator
<'a
, 'tcx
: 'a
> {
230 patch
: MirPatch
<'tcx
>,
231 tcx
: ty
::TyCtxt
<'a
, 'tcx
, 'tcx
>,
232 param_env
: &'a ty
::ParameterEnvironment
<'tcx
>,
235 impl<'a
, 'tcx
> fmt
::Debug
for DropShimElaborator
<'a
, 'tcx
> {
236 fn fmt(&self, _f
: &mut fmt
::Formatter
) -> Result
<(), fmt
::Error
> {
241 impl<'a
, 'tcx
> DropElaborator
<'a
, 'tcx
> for DropShimElaborator
<'a
, 'tcx
> {
244 fn patch(&mut self) -> &mut MirPatch
<'tcx
> { &mut self.patch }
245 fn mir(&self) -> &'a Mir
<'tcx
> { self.mir }
246 fn tcx(&self) -> ty
::TyCtxt
<'a
, 'tcx
, 'tcx
> { self.tcx }
247 fn param_env(&self) -> &'a ty
::ParameterEnvironment
<'tcx
> { self.param_env }
249 fn drop_style(&self, _path
: Self::Path
, mode
: DropFlagMode
) -> DropStyle
{
250 if let DropFlagMode
::Shallow
= mode
{
257 fn get_drop_flag(&mut self, _path
: Self::Path
) -> Option
<Operand
<'tcx
>> {
261 fn clear_drop_flag(&mut self, _location
: Location
, _path
: Self::Path
, _mode
: DropFlagMode
) {
264 fn field_subpath(&self, _path
: Self::Path
, _field
: Field
) -> Option
<Self::Path
> {
267 fn deref_subpath(&self, _path
: Self::Path
) -> Option
<Self::Path
> {
270 fn downcast_subpath(&self, _path
: Self::Path
, _variant
: usize) -> Option
<Self::Path
> {
275 /// Build a "call" shim for `def_id`. The shim calls the
276 /// function specified by `call_kind`, first adjusting its first
277 /// argument according to `rcvr_adjustment`.
279 /// If `untuple_args` is a vec of types, the second argument of the
280 /// function will be untupled as these types.
281 fn build_call_shim
<'a
, 'tcx
>(tcx
: ty
::TyCtxt
<'a
, 'tcx
, 'tcx
>,
282 param_env
: &ty
::ParameterEnvironment
<'tcx
>,
284 rcvr_adjustment
: Adjustment
,
286 untuple_args
: Option
<&[Ty
<'tcx
>]>)
289 debug
!("build_call_shim(def_id={:?}, rcvr_adjustment={:?}, \
290 call_kind={:?}, untuple_args={:?})",
291 def_id
, rcvr_adjustment
, call_kind
, untuple_args
);
293 let fn_ty
= tcx
.item_type(def_id
).subst(tcx
, param_env
.free_substs
);
294 let sig
= tcx
.erase_late_bound_regions(&fn_ty
.fn_sig());
295 let span
= tcx
.def_span(def_id
);
297 debug
!("build_call_shim: sig={:?}", sig
);
299 let mut local_decls
= local_decls_for_sig(&sig
, span
);
300 let source_info
= SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE }
;
302 let rcvr_arg
= Local
::new(1+0);
303 let rcvr_l
= Lvalue
::Local(rcvr_arg
);
304 let mut statements
= vec
![];
306 let rcvr
= match rcvr_adjustment
{
307 Adjustment
::Identity
=> Operand
::Consume(rcvr_l
),
308 Adjustment
::Deref
=> Operand
::Consume(rcvr_l
.deref()),
309 Adjustment
::RefMut
=> {
310 // let rcvr = &mut rcvr;
311 let ref_rcvr
= local_decls
.push(temp_decl(
313 tcx
.mk_ref(tcx
.types
.re_erased
, ty
::TypeAndMut
{
315 mutbl
: hir
::Mutability
::MutMutable
319 statements
.push(Statement
{
320 source_info
: source_info
,
321 kind
: StatementKind
::Assign(
322 Lvalue
::Local(ref_rcvr
),
323 Rvalue
::Ref(tcx
.types
.re_erased
, BorrowKind
::Mut
, rcvr_l
)
326 Operand
::Consume(Lvalue
::Local(ref_rcvr
))
330 let (callee
, mut args
) = match call_kind
{
331 CallKind
::Indirect
=> (rcvr
, vec
![]),
332 CallKind
::Direct(def_id
) => (
333 Operand
::Constant(box Constant
{
335 ty
: tcx
.item_type(def_id
).subst(tcx
, param_env
.free_substs
),
336 literal
: Literal
::Value
{
337 value
: ConstVal
::Function(def_id
, param_env
.free_substs
),
344 if let Some(untuple_args
) = untuple_args
{
345 args
.extend(untuple_args
.iter().enumerate().map(|(i
, ity
)| {
346 let arg_lv
= Lvalue
::Local(Local
::new(1+1));
347 Operand
::Consume(arg_lv
.field(Field
::new(i
), *ity
))
350 args
.extend((1..sig
.inputs().len()).map(|i
| {
351 Operand
::Consume(Lvalue
::Local(Local
::new(1+i
)))
355 let mut blocks
= IndexVec
::new();
356 let block
= |blocks
: &mut IndexVec
<_
, _
>, statements
, kind
, is_cleanup
| {
357 blocks
.push(BasicBlockData
{
359 terminator
: Some(Terminator { source_info, kind }
),
365 block(&mut blocks
, statements
, TerminatorKind
::Call
{
368 destination
: Some((Lvalue
::Local(RETURN_POINTER
),
369 BasicBlock
::new(1))),
370 cleanup
: if let Adjustment
::RefMut
= rcvr_adjustment
{
371 Some(BasicBlock
::new(3))
377 if let Adjustment
::RefMut
= rcvr_adjustment
{
378 // BB #1 - drop for Self
379 block(&mut blocks
, vec
![], TerminatorKind
::Drop
{
380 location
: Lvalue
::Local(rcvr_arg
),
381 target
: BasicBlock
::new(2),
386 block(&mut blocks
, vec
![], TerminatorKind
::Return
, false);
387 if let Adjustment
::RefMut
= rcvr_adjustment
{
388 // BB #3 - drop if closure panics
389 block(&mut blocks
, vec
![], TerminatorKind
::Drop
{
390 location
: Lvalue
::Local(rcvr_arg
),
391 target
: BasicBlock
::new(4),
396 block(&mut blocks
, vec
![], TerminatorKind
::Resume
, true);
399 let mut mir
= Mir
::new(
401 IndexVec
::from_elem_n(
402 VisibilityScopeData { span: span, parent_scope: None }
, 1
411 if let Abi
::RustCall
= sig
.abi
{
412 mir
.spread_arg
= Some(Local
::new(sig
.inputs().len()));
417 pub fn build_adt_ctor
<'a
, 'gcx
, 'tcx
>(infcx
: &infer
::InferCtxt
<'a
, 'gcx
, 'tcx
>,
418 ctor_id
: ast
::NodeId
,
419 fields
: &[hir
::StructField
],
421 -> (Mir
<'tcx
>, MirSource
)
424 let def_id
= tcx
.hir
.local_def_id(ctor_id
);
425 let sig
= match tcx
.item_type(def_id
).sty
{
426 ty
::TyFnDef(_
, _
, fty
) => tcx
.no_late_bound_regions(&fty
)
427 .expect("LBR in ADT constructor signature"),
428 _
=> bug
!("unexpected type for ctor {:?}", def_id
)
430 let sig
= tcx
.erase_regions(&sig
);
432 let (adt_def
, substs
) = match sig
.output().sty
{
433 ty
::TyAdt(adt_def
, substs
) => (adt_def
, substs
),
434 _
=> bug
!("unexpected type for ADT ctor {:?}", sig
.output())
437 debug
!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id
, sig
, fields
);
439 let local_decls
= local_decls_for_sig(&sig
, span
);
441 let source_info
= SourceInfo
{
443 scope
: ARGUMENT_VISIBILITY_SCOPE
446 let variant_no
= if adt_def
.is_enum() {
447 adt_def
.variant_index_with_id(def_id
)
452 // return = ADT(arg0, arg1, ...); return
453 let start_block
= BasicBlockData
{
454 statements
: vec
![Statement
{
455 source_info
: source_info
,
456 kind
: StatementKind
::Assign(
457 Lvalue
::Local(RETURN_POINTER
),
459 box AggregateKind
::Adt(adt_def
, variant_no
, substs
, None
),
460 (1..sig
.inputs().len()+1).map(|i
| {
461 Operand
::Consume(Lvalue
::Local(Local
::new(i
)))
466 terminator
: Some(Terminator
{
467 source_info
: source_info
,
468 kind
: TerminatorKind
::Return
,
474 IndexVec
::from_elem_n(start_block
, 1),
475 IndexVec
::from_elem_n(
476 VisibilityScopeData { span: span, parent_scope: None }
, 1
485 (mir
, MirSource
::Fn(ctor_id
))