diff --git a/src/librustc/ty/constness.rs b/src/librustc/ty/constness.rs
index 7298b548f3197..56f75e800f255 100644
--- a/src/librustc/ty/constness.rs
+++ b/src/librustc/ty/constness.rs
@@ -2,7 +2,7 @@ use crate::ty::query::Providers;
 use crate::hir::def_id::DefId;
 use crate::hir;
 use crate::ty::TyCtxt;
-use syntax_pos::symbol::Symbol;
+use syntax_pos::symbol::{sym, Symbol};
 use crate::hir::map::blocks::FnLikeNode;
 use syntax::attr;
 
@@ -10,27 +10,30 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
     /// Whether the `def_id` counts as const fn in your current crate, considering all active
     /// feature gates
     pub fn is_const_fn(self, def_id: DefId) -> bool {
-        self.is_const_fn_raw(def_id) && match self.lookup_stability(def_id) {
-            Some(stab) => match stab.const_stability {
+        self.is_const_fn_raw(def_id) && match self.is_unstable_const_fn(def_id) {
+            Some(feature_name) => {
                 // has a `rustc_const_unstable` attribute, check whether the user enabled the
-                // corresponding feature gate
-                Some(feature_name) => self.features()
+                // corresponding feature gate, const_constructor is not a lib feature, so has
+                // to be checked separately.
+                self.features()
                     .declared_lib_features
                     .iter()
-                    .any(|&(sym, _)| sym == feature_name),
-                // the function has no stability attribute, it is stable as const fn or the user
-                // needs to use feature gates to use the function at all
-                None => true,
+                    .any(|&(sym, _)| sym == feature_name)
+                    || (feature_name == sym::const_constructor
+                        && self.features().const_constructor)
             },
-            // functions without stability are either stable user written const fn or the user is
-            // using feature gates and we thus don't care what they do
+            // functions without const stability are either stable user written
+            // const fn or the user is using feature gates and we thus don't
+            // care what they do
             None => true,
         }
     }
 
     /// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
     pub fn is_unstable_const_fn(self, def_id: DefId) -> Option<Symbol> {
-        if self.is_const_fn_raw(def_id) {
+        if self.is_constructor(def_id) {
+            Some(sym::const_constructor)
+        } else if self.is_const_fn_raw(def_id) {
             self.lookup_stability(def_id)?.const_stability
         } else {
             None
@@ -70,8 +73,11 @@ pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
         let hir_id = tcx.hir().as_local_hir_id(def_id)
                               .expect("Non-local call to local provider is_const_fn");
 
-        if let Some(fn_like) = FnLikeNode::from_node(tcx.hir().get_by_hir_id(hir_id)) {
+        let node = tcx.hir().get_by_hir_id(hir_id);
+        if let Some(fn_like) = FnLikeNode::from_node(node) {
             fn_like.constness() == hir::Constness::Const
+        } else if let hir::Node::Ctor(_) = node {
+            true
         } else {
             false
         }
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 10ff606b013a7..e3e327d0a5bd0 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -1167,6 +1167,7 @@ impl<'a, 'tcx> CrateMetadata {
         let constness = match self.entry(id).kind {
             EntryKind::Method(data) => data.decode(self).fn_data.constness,
             EntryKind::Fn(data) => data.decode(self).constness,
+            EntryKind::Variant(..) | EntryKind::Struct(..) => hir::Constness::Const,
             _ => hir::Constness::NotConst,
         };
         constness == hir::Constness::Const
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index 4ae4d039d6034..74b2faa7a4ce8 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 c8a31ecffb84d..6bde349390ee8 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 9213a009ea740..53302810b4052 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 0cefc8c3a92ab..169e426c1d3c6 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 7da37f956cedd..286c412622dd5 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 82193d98655d6..cc8aaa1c97fb3 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 0000000000000..98e70671ab715
--- /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 0e7f473a3e70d..e340029434d81 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/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 4a95b6f69a161..0043b8a1c47c4 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -560,6 +560,10 @@ declare_features! (
     // Allows the user of associated type bounds.
     (active, associated_type_bounds, "1.34.0", Some(52662), None),
 
+    // Allows calling constructor functions in `const fn`
+    // FIXME Create issue
+    (active, const_constructor, "1.37.0", Some(61456), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 4e080d115d2a8..6fac343581427 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -185,6 +185,7 @@ symbols! {
         conservative_impl_trait,
         console,
         const_compare_raw_pointers,
+        const_constructor,
         const_fn,
         const_fn_union,
         const_generics,
diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs
index 67a55101d829f..f4d848dfc7ad1 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;
 //     }
 // }
diff --git a/src/test/ui/consts/const_constructor/const-construct-call.rs b/src/test/ui/consts/const_constructor/const-construct-call.rs
new file mode 100644
index 0000000000000..f2d2bda53c053
--- /dev/null
+++ b/src/test/ui/consts/const_constructor/const-construct-call.rs
@@ -0,0 +1,116 @@
+// Test that constructors are considered to be const fns with the required feature.
+
+// run-pass
+
+// revisions: min_const_fn const_fn
+
+#![cfg_attr(const_fn, feature(const_fn))]
+
+#![feature(const_constructor)]
+
+// Ctor(..) is transformed to Ctor { 0: ... } in HAIR lowering, so directly
+// calling constructors doesn't require them to be const.
+
+type ExternalType = std::panic::AssertUnwindSafe<(Option<i32>, Result<i32, bool>)>;
+
+const fn call_external_constructors_in_local_vars() -> ExternalType {
+    let f = Some;
+    let g = Err;
+    let h = std::panic::AssertUnwindSafe;
+    let x = f(5);
+    let y = g(false);
+    let z = h((x, y));
+    z
+}
+
+const CALL_EXTERNAL_CONSTRUCTORS_IN_LOCAL_VARS: ExternalType = {
+    let f = Some;
+    let g = Err;
+    let h = std::panic::AssertUnwindSafe;
+    let x = f(5);
+    let y = g(false);
+    let z = h((x, y));
+    z
+};
+
+const fn call_external_constructors_in_temps() -> ExternalType {
+    let x = { Some }(5);
+    let y = (*&Err)(false);
+    let z = [std::panic::AssertUnwindSafe][0]((x, y));
+    z
+}
+
+const CALL_EXTERNAL_CONSTRUCTORS_IN_TEMPS: ExternalType = {
+    let x = { Some }(5);
+    let y = (*&Err)(false);
+    let z = [std::panic::AssertUnwindSafe][0]((x, y));
+    z
+};
+
+#[derive(Debug, PartialEq)]
+enum LocalOption<T> {
+    Some(T),
+    _None,
+}
+
+#[derive(Debug, PartialEq)]
+enum LocalResult<T, E> {
+    _Ok(T),
+    Err(E),
+}
+
+#[derive(Debug, PartialEq)]
+struct LocalAssertUnwindSafe<T>(T);
+
+type LocalType = LocalAssertUnwindSafe<(LocalOption<i32>, LocalResult<i32, bool>)>;
+
+const fn call_local_constructors_in_local_vars() -> LocalType {
+    let f = LocalOption::Some;
+    let g = LocalResult::Err;
+    let h = LocalAssertUnwindSafe;
+    let x = f(5);
+    let y = g(false);
+    let z = h((x, y));
+    z
+}
+
+const CALL_LOCAL_CONSTRUCTORS_IN_LOCAL_VARS: LocalType = {
+    let f = LocalOption::Some;
+    let g = LocalResult::Err;
+    let h = LocalAssertUnwindSafe;
+    let x = f(5);
+    let y = g(false);
+    let z = h((x, y));
+    z
+};
+
+const fn call_local_constructors_in_temps() -> LocalType {
+    let x = { LocalOption::Some }(5);
+    let y = (*&LocalResult::Err)(false);
+    let z = [LocalAssertUnwindSafe][0]((x, y));
+    z
+}
+
+const CALL_LOCAL_CONSTRUCTORS_IN_TEMPS: LocalType = {
+    let x = { LocalOption::Some }(5);
+    let y = (*&LocalResult::Err)(false);
+    let z = [LocalAssertUnwindSafe][0]((x, y));
+    z
+};
+
+fn main() {
+    assert_eq!(
+        (
+            call_external_constructors_in_local_vars().0,
+            call_external_constructors_in_temps().0,
+            call_local_constructors_in_local_vars(),
+            call_local_constructors_in_temps(),
+        ),
+        (
+            CALL_EXTERNAL_CONSTRUCTORS_IN_LOCAL_VARS.0,
+            CALL_EXTERNAL_CONSTRUCTORS_IN_TEMPS.0,
+            CALL_LOCAL_CONSTRUCTORS_IN_LOCAL_VARS,
+            CALL_LOCAL_CONSTRUCTORS_IN_TEMPS,
+        )
+    );
+}
diff --git a/src/test/ui/consts/const_constructor/feature-gate-const_constructor.const_fn.stderr b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.const_fn.stderr
new file mode 100644
index 0000000000000..fa4f83ed01e15
--- /dev/null
+++ b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.const_fn.stderr
@@ -0,0 +1,34 @@
+error: `std::prelude::v1::Some` is not yet stable as a const fn
+  --> $DIR/feature-gate-const_constructor.rs:9:37
+   |
+LL | const EXTERNAL_CONST: Option<i32> = {Some}(1);
+   |                                     ^^^^^^^^^
+   |
+   = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `E::V` is not yet stable as a const fn
+  --> $DIR/feature-gate-const_constructor.rs:12:24
+   |
+LL | const LOCAL_CONST: E = {E::V}(1);
+   |                        ^^^^^^^^^
+   |
+   = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `std::prelude::v1::Some` is not yet stable as a const fn
+  --> $DIR/feature-gate-const_constructor.rs:17:13
+   |
+LL |     let _ = {Some}(1);
+   |             ^^^^^^^^^
+   |
+   = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `E::V` is not yet stable as a const fn
+  --> $DIR/feature-gate-const_constructor.rs:23:13
+   |
+LL |     let _ = {E::V}(1);
+   |             ^^^^^^^^^
+   |
+   = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/consts/const_constructor/feature-gate-const_constructor.min_const_fn.stderr b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.min_const_fn.stderr
new file mode 100644
index 0000000000000..fa4f83ed01e15
--- /dev/null
+++ b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.min_const_fn.stderr
@@ -0,0 +1,34 @@
+error: `std::prelude::v1::Some` is not yet stable as a const fn
+  --> $DIR/feature-gate-const_constructor.rs:9:37
+   |
+LL | const EXTERNAL_CONST: Option<i32> = {Some}(1);
+   |                                     ^^^^^^^^^
+   |
+   = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `E::V` is not yet stable as a const fn
+  --> $DIR/feature-gate-const_constructor.rs:12:24
+   |
+LL | const LOCAL_CONST: E = {E::V}(1);
+   |                        ^^^^^^^^^
+   |
+   = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `std::prelude::v1::Some` is not yet stable as a const fn
+  --> $DIR/feature-gate-const_constructor.rs:17:13
+   |
+LL |     let _ = {Some}(1);
+   |             ^^^^^^^^^
+   |
+   = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: `E::V` is not yet stable as a const fn
+  --> $DIR/feature-gate-const_constructor.rs:23:13
+   |
+LL |     let _ = {E::V}(1);
+   |             ^^^^^^^^^
+   |
+   = help: add `#![feature(const_constructor)]` to the crate attributes to enable
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/consts/const_constructor/feature-gate-const_constructor.rs b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.rs
new file mode 100644
index 0000000000000..b37fd2fd243d1
--- /dev/null
+++ b/src/test/ui/consts/const_constructor/feature-gate-const_constructor.rs
@@ -0,0 +1,28 @@
+// revisions: min_const_fn const_fn
+
+#![cfg_attr(const_fn, feature(const_fn))]
+
+enum E {
+    V(i32),
+}
+
+const EXTERNAL_CONST: Option<i32> = {Some}(1);
+//[min_const_fn]~^ ERROR is not yet stable as a const fn
+//[const_fn]~^^ ERROR is not yet stable as a const fn
+const LOCAL_CONST: E = {E::V}(1);
+//[min_const_fn]~^ ERROR is not yet stable as a const fn
+//[const_fn]~^^ ERROR is not yet stable as a const fn
+
+const fn external_fn() {
+    let _ = {Some}(1);
+    //[min_const_fn]~^ ERROR is not yet stable as a const fn
+    //[const_fn]~^^ ERROR is not yet stable as a const fn
+}
+
+const fn local_fn() {
+    let _ = {E::V}(1);
+    //[min_const_fn]~^ ERROR is not yet stable as a const fn
+    //[const_fn]~^^ ERROR is not yet stable as a const fn
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.rs b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.rs
new file mode 100644
index 0000000000000..116583223925a
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.rs
@@ -0,0 +1,71 @@
+// Unit test for the "user substitutions" that are annotated on each
+// node.
+
+struct SomeStruct<T>(T);
+
+fn no_annot() {
+    let c = 66;
+    let f = SomeStruct;
+    f(&c);
+}
+
+fn annot_underscore() {
+    let c = 66;
+    let f = SomeStruct::<_>;
+    f(&c);
+}
+
+fn annot_reference_any_lifetime() {
+    let c = 66;
+    let f = SomeStruct::<&u32>;
+    f(&c);
+}
+
+fn annot_reference_static_lifetime() {
+    let c = 66;
+    let f = SomeStruct::<&'static u32>;
+    f(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+    let c = 66;
+    let f = SomeStruct::<&'a u32>;
+    f(&c); //~ ERROR
+}
+
+fn annot_reference_named_lifetime_ok<'a>(c: &'a u32) {
+    let f = SomeStruct::<&'a u32>;
+    f(c);
+}
+
+fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+    let _closure = || {
+        let c = 66;
+        let f = SomeStruct::<&'a u32>;
+        f(&c); //~ ERROR
+    };
+}
+
+fn annot_reference_named_lifetime_across_closure<'a>(_: &'a u32) {
+    let f = SomeStruct::<&'a u32>;
+    let _closure = || {
+        let c = 66;
+        f(&c); //~ ERROR
+    };
+}
+
+fn annot_reference_named_lifetime_in_closure_ok<'a>(c: &'a u32) {
+    let _closure = || {
+        let f = SomeStruct::<&'a u32>;
+        f(c);
+    };
+}
+
+fn annot_reference_named_lifetime_across_closure_ok<'a>(c: &'a u32) {
+    let f = SomeStruct::<&'a u32>;
+    let _closure = || {
+        f(c);
+    };
+}
+
+fn main() { }
diff --git a/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr
new file mode 100644
index 0000000000000..9664fb9f54831
--- /dev/null
+++ b/src/test/ui/nll/user-annotations/adt-tuple-struct-calls.stderr
@@ -0,0 +1,56 @@
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-tuple-struct-calls.rs:27:7
+   |
+LL |     f(&c);
+   |     --^^-
+   |     | |
+   |     | borrowed value does not live long enough
+   |     argument requires that `c` is borrowed for `'static`
+LL | }
+   | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-tuple-struct-calls.rs:33:7
+   |
+LL | fn annot_reference_named_lifetime<'a>(_d: &'a u32) {
+   |                                   -- lifetime `'a` defined here
+...
+LL |     f(&c);
+   |     --^^-
+   |     | |
+   |     | borrowed value does not live long enough
+   |     argument requires that `c` is borrowed for `'a`
+LL | }
+   | - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-tuple-struct-calls.rs:45:11
+   |
+LL | fn annot_reference_named_lifetime_in_closure<'a>(_: &'a u32) {
+   |                                              -- lifetime `'a` defined here
+...
+LL |         f(&c);
+   |         --^^-
+   |         | |
+   |         | borrowed value does not live long enough
+   |         argument requires that `c` is borrowed for `'a`
+LL |     };
+   |     - `c` dropped here while still borrowed
+
+error[E0597]: `c` does not live long enough
+  --> $DIR/adt-tuple-struct-calls.rs:53:11
+   |
+LL |     let f = SomeStruct::<&'a u32>;
+   |         - lifetime `'1` appears in the type of `f`
+...
+LL |         f(&c);
+   |         --^^-
+   |         | |
+   |         | borrowed value does not live long enough
+   |         argument requires that `c` is borrowed for `'1`
+LL |     };
+   |     - `c` dropped here while still borrowed
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0597`.