about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/borrow_check/mod.rs28
-rw-r--r--src/librustc_mir/build/mod.rs35
-rw-r--r--src/librustc_mir/lib.rs1
-rw-r--r--src/librustc_mir/shim.rs82
-rw-r--r--src/librustc_mir/transform/deaggregator.rs68
-rw-r--r--src/librustc_mir/transform/mod.rs12
-rw-r--r--src/librustc_mir/util/aggregate.rs76
-rw-r--r--src/librustc_mir/util/mod.rs2
-rw-r--r--src/test/mir-opt/unusual-item-types.rs3
9 files changed, 152 insertions, 155 deletions
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 4ae4d039d60..74b2faa7a4c 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -91,34 +91,6 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> BorrowC
     let input_mir = tcx.mir_validated(def_id);
     debug!("run query mir_borrowck: {}", tcx.def_path_str(def_id));
 
-    // We are not borrow checking the automatically generated struct/variant constructors
-    // because we want to accept structs such as this (taken from the `linked-hash-map`
-    // crate):
-    // ```rust
-    // struct Qey<Q: ?Sized>(Q);
-    // ```
-    // MIR of this struct constructor looks something like this:
-    // ```rust
-    // fn Qey(_1: Q) -> Qey<Q>{
-    //     let mut _0: Qey<Q>;                  // return place
-    //
-    //     bb0: {
-    //         (_0.0: Q) = move _1;             // bb0[0]: scope 0 at src/main.rs:1:1: 1:26
-    //         return;                          // bb0[1]: scope 0 at src/main.rs:1:1: 1:26
-    //     }
-    // }
-    // ```
-    // The problem here is that `(_0.0: Q) = move _1;` is valid only if `Q` is
-    // of statically known size, which is not known to be true because of the
-    // `Q: ?Sized` constraint. However, it is true because the constructor can be
-    // called only when `Q` is of statically known size.
-    if tcx.is_constructor(def_id) {
-        return BorrowCheckResult {
-            closure_requirements: None,
-            used_mut_upvars: SmallVec::new(),
-        };
-    }
-
     let opt_closure_req = tcx.infer_ctxt().enter(|infcx| {
         let input_mir: &Body<'_> = &input_mir.borrow();
         do_mir_borrowck(&infcx, input_mir, def_id)
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index c8a31ecffb8..6bde349390e 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -2,7 +2,6 @@ use crate::build;
 use crate::build::scope::DropKind;
 use crate::hair::cx::Cx;
 use crate::hair::{LintLevel, BindingMode, PatternKind};
-use crate::shim;
 use crate::transform::MirSource;
 use crate::util as mir_util;
 use rustc::hir;
@@ -31,8 +30,6 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Body<'
 
     // Figure out what primary body this item has.
     let (body_id, return_ty_span) = match tcx.hir().get_by_hir_id(id) {
-        Node::Ctor(ctor) => return create_constructor_shim(tcx, id, ctor),
-
         Node::Expr(hir::Expr { node: hir::ExprKind::Closure(_, decl, body_id, _, _), .. })
         | Node::Item(hir::Item { node: hir::ItemKind::Fn(decl, _, _, body_id), .. })
         | Node::ImplItem(
@@ -234,38 +231,6 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> {
     }
 }
 
-fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     ctor_id: hir::HirId,
-                                     v: &'tcx hir::VariantData)
-                                     -> Body<'tcx>
-{
-    let span = tcx.hir().span_by_hir_id(ctor_id);
-    if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
-        tcx.infer_ctxt().enter(|infcx| {
-            let mut mir = shim::build_adt_ctor(&infcx, ctor_id, fields, span);
-
-            // Convert the `mir::Body` to global types.
-            let tcx = infcx.tcx.global_tcx();
-            let mut globalizer = GlobalizeMir {
-                tcx,
-                span: mir.span
-            };
-            globalizer.visit_body(&mut mir);
-            let mir = unsafe {
-                mem::transmute::<Body<'_>, Body<'tcx>>(mir)
-            };
-
-            mir_util::dump_mir(tcx, None, "mir_map", &0,
-                               MirSource::item(tcx.hir().local_def_id_from_hir_id(ctor_id)),
-                               &mir, |_, _| Ok(()) );
-
-            mir
-        })
-    } else {
-        span_bug!(span, "attempting to create MIR for non-tuple variant {:?}", v);
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // BuildMir -- walks a crate, looking for fn items and methods to build MIR from
 
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 9213a009ea7..53302810b40 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -22,6 +22,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 #![feature(unicode_internals)]
 #![feature(step_trait)]
 #![feature(slice_concat_ext)]
+#![feature(trusted_len)]
 #![feature(try_blocks)]
 
 #![recursion_limit="256"]
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 0cefc8c3a92..169e426c1d3 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -1,6 +1,5 @@
 use rustc::hir;
 use rustc::hir::def_id::DefId;
-use rustc::infer;
 use rustc::mir::*;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::VariantIdx;
@@ -21,6 +20,7 @@ use crate::transform::{
 };
 use crate::util::elaborate_drops::{self, DropElaborator, DropStyle, DropFlagMode};
 use crate::util::patch::MirPatch;
+use crate::util::expand_aggregate;
 
 pub fn provide(providers: &mut Providers<'_>) {
     providers.mir_shims = make_shim;
@@ -842,29 +842,26 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     mir
 }
 
-pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
-                                      ctor_id: hir::HirId,
-                                      fields: &[hir::StructField],
-                                      span: Span)
-                                      -> Body<'tcx>
-{
-    let tcx = infcx.tcx;
-    let gcx = tcx.global_tcx();
-    let def_id = tcx.hir().local_def_id_from_hir_id(ctor_id);
-    let param_env = gcx.param_env(def_id);
+pub fn build_adt_ctor<'gcx>(tcx: TyCtxt<'_, 'gcx, 'gcx>, ctor_id: DefId) -> &'gcx Body<'gcx> {
+    debug_assert!(tcx.is_constructor(ctor_id));
+
+    let span = tcx.hir().span_if_local(ctor_id)
+        .unwrap_or_else(|| bug!("no span for ctor {:?}", ctor_id));
+
+    let param_env = tcx.param_env(ctor_id);
 
     // Normalize the sig.
-    let sig = gcx.fn_sig(def_id)
+    let sig = tcx.fn_sig(ctor_id)
         .no_bound_vars()
         .expect("LBR in ADT constructor signature");
-    let sig = gcx.normalize_erasing_regions(param_env, sig);
+    let sig = tcx.normalize_erasing_regions(param_env, sig);
 
     let (adt_def, substs) = match sig.output().sty {
         ty::Adt(adt_def, substs) => (adt_def, substs),
         _ => bug!("unexpected type for ADT ctor {:?}", sig.output())
     };
 
-    debug!("build_ctor: def_id={:?} sig={:?} fields={:?}", def_id, sig, fields);
+    debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig);
 
     let local_decls = local_decls_for_sig(&sig, span);
 
@@ -873,26 +870,37 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
         scope: OUTERMOST_SOURCE_SCOPE
     };
 
-    let variant_no = if adt_def.is_enum() {
-        adt_def.variant_index_with_ctor_id(def_id)
+    let variant_index = if adt_def.is_enum() {
+        adt_def.variant_index_with_ctor_id(ctor_id)
     } else {
         VariantIdx::new(0)
     };
 
-    // return = ADT(arg0, arg1, ...); return
+    // Generate the following MIR:
+    //
+    // (return as Variant).field0 = arg0;
+    // (return as Variant).field1 = arg1;
+    //
+    // return;
+    debug!("build_ctor: variant_index={:?}", variant_index);
+
+    let statements = expand_aggregate(
+        Place::RETURN_PLACE,
+        adt_def
+            .variants[variant_index]
+            .fields
+            .iter()
+            .enumerate()
+            .map(|(idx, field_def)| (
+                Operand::Move(Place::Base(PlaceBase::Local(Local::new(idx + 1)))),
+                field_def.ty(tcx, substs),
+            )),
+        AggregateKind::Adt(adt_def, variant_index, substs, None, None),
+        source_info,
+    ).collect();
+
     let start_block = BasicBlockData {
-        statements: vec![Statement {
-            source_info,
-            kind: StatementKind::Assign(
-                Place::RETURN_PLACE,
-                box Rvalue::Aggregate(
-                    box AggregateKind::Adt(adt_def, variant_no, substs, None, None),
-                    (1..sig.inputs().len()+1).map(|i| {
-                        Operand::Move(Place::Base(PlaceBase::Local(Local::new(i))))
-                    }).collect()
-                )
-            )
-        }],
+        statements,
         terminator: Some(Terminator {
             source_info,
             kind: TerminatorKind::Return,
@@ -900,7 +908,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
         is_cleanup: false
     };
 
-    Body::new(
+    let body = Body::new(
         IndexVec::from_elem_n(start_block, 1),
         IndexVec::from_elem_n(
             SourceScopeData { span: span, parent_scope: None }, 1
@@ -914,5 +922,17 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
         vec![],
         span,
         vec![],
-    )
+    );
+
+    crate::util::dump_mir(
+        tcx,
+        None,
+        "mir_map",
+        &0,
+        crate::transform::MirSource::item(ctor_id),
+        &body,
+        |_, _| Ok(()),
+    );
+
+    tcx.arena.alloc(body)
 }
diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs
index 7da37f956ce..286c412622d 100644
--- a/src/librustc_mir/transform/deaggregator.rs
+++ b/src/librustc_mir/transform/deaggregator.rs
@@ -1,8 +1,7 @@
 use rustc::mir::*;
 use rustc::ty::TyCtxt;
-use rustc::ty::layout::VariantIdx;
-use rustc_data_structures::indexed_vec::Idx;
 use crate::transform::{MirPass, MirSource};
+use crate::util::expand_aggregate;
 
 pub struct Deaggregator;
 
@@ -31,7 +30,7 @@ impl MirPass for Deaggregator {
 
                 let stmt = stmt.replace_nop();
                 let source_info = stmt.source_info;
-                let (mut lhs, kind, operands) = match stmt.kind {
+                let (lhs, kind, operands) = match stmt.kind {
                     StatementKind::Assign(lhs, box rvalue) => {
                         match rvalue {
                             Rvalue::Aggregate(kind, operands) => (lhs, kind, operands),
@@ -41,62 +40,15 @@ impl MirPass for Deaggregator {
                     _ => bug!()
                 };
 
-                let mut set_discriminant = None;
-                let active_field_index = match *kind {
-                    AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
-                        if adt_def.is_enum() {
-                            set_discriminant = Some(Statement {
-                                kind: StatementKind::SetDiscriminant {
-                                    place: lhs.clone(),
-                                    variant_index,
-                                },
-                                source_info,
-                            });
-                            lhs = lhs.downcast(adt_def, variant_index);
-                        }
-                        active_field_index
-                    }
-                    AggregateKind::Generator(..) => {
-                        // Right now we only support initializing generators to
-                        // variant 0 (Unresumed).
-                        let variant_index = VariantIdx::new(0);
-                        set_discriminant = Some(Statement {
-                            kind: StatementKind::SetDiscriminant {
-                                place: lhs.clone(),
-                                variant_index,
-                            },
-                            source_info,
-                        });
-
-                        // Operands are upvars stored on the base place, so no
-                        // downcast is necessary.
-
-                        None
-                    }
-                    _ => None
-                };
-
-                Some(operands.into_iter().enumerate().map(move |(i, op)| {
-                    let lhs_field = if let AggregateKind::Array(_) = *kind {
-                        // FIXME(eddyb) `offset` should be u64.
-                        let offset = i as u32;
-                        assert_eq!(offset as usize, i);
-                        lhs.clone().elem(ProjectionElem::ConstantIndex {
-                            offset,
-                            // FIXME(eddyb) `min_length` doesn't appear to be used.
-                            min_length: offset + 1,
-                            from_end: false
-                        })
-                    } else {
+                Some(expand_aggregate(
+                    lhs,
+                    operands.into_iter().map(|op| {
                         let ty = op.ty(local_decls, tcx);
-                        let field = Field::new(active_field_index.unwrap_or(i));
-                        lhs.clone().field(field, ty)
-                    };
-                    Statement {
-                        source_info,
-                        kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
-                    }
-                }).chain(set_discriminant))
+                        (op, ty)
+                    }),
+                    *kind,
+                    source_info,
+                ))
             });
         }
     }
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 82193d98655..cc8aaa1c97f 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -1,4 +1,4 @@
-use crate::build;
+use crate::{build, shim};
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::mir::{Body, MirPhase, Promoted};
 use rustc::ty::{TyCtxt, InstanceDef};
@@ -228,7 +228,15 @@ fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
 }
 
 fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
-    // `mir_borrowck` uses `mir_validated`, so we have to force it to
+    if tcx.is_constructor(def_id) {
+        // There's no reason to run all of the MIR passes on constructors when
+        // we can just output the MIR we want directly. This also saves const
+        // qualification and borrow checking the trouble of special casing
+        // constructors.
+        return shim::build_adt_ctor(tcx, def_id);
+    }
+
+    // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
     // execute before we can steal.
     tcx.ensure().mir_borrowck(def_id);
 
diff --git a/src/librustc_mir/util/aggregate.rs b/src/librustc_mir/util/aggregate.rs
new file mode 100644
index 00000000000..98e70671ab7
--- /dev/null
+++ b/src/librustc_mir/util/aggregate.rs
@@ -0,0 +1,76 @@
+use rustc::mir::*;
+use rustc::ty::Ty;
+use rustc::ty::layout::VariantIdx;
+use rustc_data_structures::indexed_vec::Idx;
+
+use std::iter::TrustedLen;
+
+/// Expand `lhs = Rvalue::Aggregate(kind, operands)` into assignments to the fields.
+///
+/// Produces something like
+///
+/// (lhs as Variant).field0 = arg0;     // We only have a downcast if this is an enum
+/// (lhs as Variant).field1 = arg1;
+/// discriminant(lhs) = variant_index;  // If lhs is an enum or generator.
+pub fn expand_aggregate<'tcx>(
+    mut lhs: Place<'tcx>,
+    operands: impl Iterator<Item=(Operand<'tcx>, Ty<'tcx>)> + TrustedLen,
+    kind: AggregateKind<'tcx>,
+    source_info: SourceInfo,
+) -> impl Iterator<Item=Statement<'tcx>> + TrustedLen {
+    let mut set_discriminant = None;
+    let active_field_index = match kind {
+        AggregateKind::Adt(adt_def, variant_index, _, _, active_field_index) => {
+            if adt_def.is_enum() {
+                set_discriminant = Some(Statement {
+                    kind: StatementKind::SetDiscriminant {
+                        place: lhs.clone(),
+                        variant_index,
+                    },
+                    source_info,
+                });
+                lhs = lhs.downcast(adt_def, variant_index);
+            }
+            active_field_index
+        }
+        AggregateKind::Generator(..) => {
+            // Right now we only support initializing generators to
+            // variant 0 (Unresumed).
+            let variant_index = VariantIdx::new(0);
+            set_discriminant = Some(Statement {
+                kind: StatementKind::SetDiscriminant {
+                    place: lhs.clone(),
+                    variant_index,
+                },
+                source_info,
+            });
+
+            // Operands are upvars stored on the base place, so no
+            // downcast is necessary.
+
+            None
+        }
+        _ => None
+    };
+
+    operands.into_iter().enumerate().map(move |(i, (op, ty))| {
+        let lhs_field = if let AggregateKind::Array(_) = kind {
+            // FIXME(eddyb) `offset` should be u64.
+            let offset = i as u32;
+            assert_eq!(offset as usize, i);
+            lhs.clone().elem(ProjectionElem::ConstantIndex {
+                offset,
+                // FIXME(eddyb) `min_length` doesn't appear to be used.
+                min_length: offset + 1,
+                from_end: false
+            })
+        } else {
+            let field = Field::new(active_field_index.unwrap_or(i));
+            lhs.clone().field(field, ty)
+        };
+        Statement {
+            source_info,
+            kind: StatementKind::Assign(lhs_field, box Rvalue::Use(op)),
+        }
+    }).chain(set_discriminant)
+}
diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs
index 0e7f473a3e7..e340029434d 100644
--- a/src/librustc_mir/util/mod.rs
+++ b/src/librustc_mir/util/mod.rs
@@ -2,6 +2,7 @@ use core::unicode::property::Pattern_White_Space;
 use rustc::ty::TyCtxt;
 use syntax_pos::Span;
 
+pub mod aggregate;
 pub mod borrowck_errors;
 pub mod elaborate_drops;
 pub mod def_use;
@@ -13,6 +14,7 @@ pub(crate) mod pretty;
 pub mod liveness;
 pub mod collect_writes;
 
+pub use self::aggregate::expand_aggregate;
 pub use self::alignment::is_disaligned;
 pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere};
 pub use self::graphviz::{graphviz_safe_def_name, write_mir_graphviz};
diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs
index 67a55101d82..f4d848dfc7a 100644
--- a/src/test/mir-opt/unusual-item-types.rs
+++ b/src/test/mir-opt/unusual-item-types.rs
@@ -78,7 +78,8 @@ fn main() {
 //     let mut _0: Test;
 //
 //     bb0: {
-//         _0 = Test::X(move _1,);
+//         ((_0 as X).0: usize) = move _1;
+//         discriminant(_0) = 0;
 //         return;
 //     }
 // }