]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #35162 - canndrew:bang_type_coerced, r=nikomatsakis
authorbors <bors@rust-lang.org>
Tue, 16 Aug 2016 07:12:12 +0000 (00:12 -0700)
committerGitHub <noreply@github.com>
Tue, 16 Aug 2016 07:12:12 +0000 (00:12 -0700)
Implement the `!` type

This implements the never type (`!`) and hides it behind the feature gate `#[feature(never_type)]`. With the feature gate off, things should build as normal (although some error messages may be different). With the gate on, `!` is usable as a type and diverging type variables (ie. types that are unconstrained by anything in the code) will default to `!` instead of `()`.

18 files changed:
1  2 
src/librustc/mir/repr.rs
src/librustc/mir/visit.rs
src/librustc/ty/error.rs
src/librustc_borrowck/borrowck/mir/gather_moves.rs
src/librustc_const_eval/check_match.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/transform/promote_consts.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustc_mir/transform/type_check.rs
src/librustc_privacy/lib.rs
src/librustc_trans/base.rs
src/librustc_trans/collector.rs
src/librustc_trans/mir/analyze.rs
src/librustc_typeck/check/intrinsic.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/op.rs
src/libsyntax/feature_gate.rs
src/libsyntax/parse/parser.rs

diff --combined src/librustc/mir/repr.rs
index 454c1ff816753cbcbc955048cd111e504891318c,549026290c9d561f4d712bdc06040abc915916a3..2bde3d6554feef4400767c15037e19aa4e2955b6
@@@ -17,7 -17,7 +17,7 @@@ use rustc_data_structures::control_flow
  use rustc_data_structures::control_flow_graph::ControlFlowGraph;
  use hir::def_id::DefId;
  use ty::subst::Substs;
- use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
+ use ty::{self, AdtDef, ClosureSubsts, Region, Ty};
  use util::ppaux;
  use rustc_back::slice;
  use hir::InlineAsm;
@@@ -74,7 -74,7 +74,7 @@@ pub struct Mir<'tcx> 
      pub promoted: IndexVec<Promoted, Mir<'tcx>>,
  
      /// Return type of the function.
-     pub return_ty: FnOutput<'tcx>,
+     pub return_ty: Ty<'tcx>,
  
      /// Variables: these are stack slots corresponding to user variables. They may be
      /// assigned many times.
@@@ -107,7 -107,7 +107,7 @@@ impl<'tcx> Mir<'tcx> 
      pub fn new(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
                 visibility_scopes: IndexVec<VisibilityScope, VisibilityScopeData>,
                 promoted: IndexVec<Promoted, Mir<'tcx>>,
-                return_ty: FnOutput<'tcx>,
+                return_ty: Ty<'tcx>,
                 var_decls: IndexVec<Var, VarDecl<'tcx>>,
                 arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
                 temp_decls: IndexVec<Temp, TempDecl<'tcx>>,
@@@ -688,17 -688,8 +688,17 @@@ pub struct Statement<'tcx> 
  
  #[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
  pub enum StatementKind<'tcx> {
 +    /// Write the RHS Rvalue to the LHS Lvalue.
      Assign(Lvalue<'tcx>, Rvalue<'tcx>),
 -    SetDiscriminant{ lvalue: Lvalue<'tcx>, variant_index: usize },
 +
 +    /// Write the discriminant for a variant to the enum Lvalue.
 +    SetDiscriminant { lvalue: Lvalue<'tcx>, variant_index: usize },
 +
 +    /// Start a live range for the storage of the local.
 +    StorageLive(Lvalue<'tcx>),
 +
 +    /// End the current live range for the storage of the local.
 +    StorageDead(Lvalue<'tcx>),
  }
  
  impl<'tcx> Debug for Statement<'tcx> {
          use self::StatementKind::*;
          match self.kind {
              Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv),
 +            StorageLive(ref lv) => write!(fmt, "StorageLive({:?})", lv),
 +            StorageDead(ref lv) => write!(fmt, "StorageDead({:?})", lv),
              SetDiscriminant{lvalue: ref lv, variant_index: index} => {
                  write!(fmt, "discriminant({:?}) = {:?}", lv, index)
              }
index d3526f618a904e142675f76838412ce1ed6523ea,66cdc7f156d9c1370c1ff36a120108846a0ad70c..ead8de86dbae4094f555d09068fde43057d6a0cf
@@@ -11,7 -11,7 +11,7 @@@
  use middle::const_val::ConstVal;
  use hir::def_id::DefId;
  use ty::subst::Substs;
- use ty::{ClosureSubsts, FnOutput, Region, Ty};
+ use ty::{ClosureSubsts, Region, Ty};
  use mir::repr::*;
  use rustc_const_math::ConstUsize;
  use rustc_data_structures::tuple_slice::TupleSlice;
@@@ -38,9 -38,7 +38,7 @@@ use syntax_pos::Span
  //
  // For the most part, we do not destructure things external to the
  // MIR, e.g. types, spans, etc, but simply visit them and stop. This
- // avoids duplication with other visitors like `TypeFoldable`. But
- // there is one exception: we do destructure the `FnOutput` to reach
- // the type within. Just because.
+ // avoids duplication with other visitors like `TypeFoldable`.
  //
  // ## Updating
  //
@@@ -192,11 -190,6 +190,6 @@@ macro_rules! make_mir_visitor 
                  self.super_source_info(source_info);
              }
  
-             fn visit_fn_output(&mut self,
-                                fn_output: & $($mutability)* FnOutput<'tcx>) {
-                 self.super_fn_output(fn_output);
-             }
              fn visit_ty(&mut self,
                          ty: & $($mutability)* Ty<'tcx>) {
                  self.super_ty(ty);
                      self.visit_visibility_scope_data(scope);
                  }
  
-                 self.visit_fn_output(&$($mutability)* mir.return_ty);
+                 self.visit_ty(&$($mutability)* mir.return_ty);
  
                  for var_decl in &$($mutability)* mir.var_decls {
                      self.visit_var_decl(var_decl);
                      StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
                          self.visit_lvalue(lvalue, LvalueContext::Store);
                      }
 +                    StatementKind::StorageLive(ref $($mutability)* lvalue) => {
 +                        self.visit_lvalue(lvalue, LvalueContext::StorageLive);
 +                    }
 +                    StatementKind::StorageDead(ref $($mutability)* lvalue) => {
 +                        self.visit_lvalue(lvalue, LvalueContext::StorageDead);
 +                    }
                  }
              }
  
                  self.visit_visibility_scope(scope);
              }
  
-             fn super_fn_output(&mut self, fn_output: & $($mutability)* FnOutput<'tcx>) {
-                 match *fn_output {
-                     FnOutput::FnConverging(ref $($mutability)* ty) => {
-                         self.visit_ty(ty);
-                     }
-                     FnOutput::FnDiverging => {
-                     }
-                 }
-             }
              fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
              }
  
@@@ -765,8 -742,4 +748,8 @@@ pub enum LvalueContext 
  
      // Consumed as part of an operand
      Consume,
 +
 +    // Starting and ending a storage live range
 +    StorageLive,
 +    StorageDead,
  }
diff --combined src/librustc/ty/error.rs
index 6b34c0a21988dd81ecf6246b1aeee854cab71888,dab9c246d5f1b02291ddaff19cc6732d32fa6e2f..42d5788568f1c246ac72ae746c74452ffe0d1f2d
@@@ -214,7 -214,7 +214,7 @@@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx
      fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String {
          match self.sty {
              ty::TyBool | ty::TyChar | ty::TyInt(_) |
-             ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr => self.to_string(),
+             ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(),
              ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(),
  
              ty::TyEnum(def, _) => format!("enum `{}`", tcx.item_path_str(def.did)),
              ty::TyArray(_, n) => format!("array of {} elements", n),
              ty::TySlice(_) => "slice".to_string(),
              ty::TyRawPtr(_) => "*-ptr".to_string(),
 -            ty::TyRef(_, _) => "&-ptr".to_string(),
 +            ty::TyRef(region, tymut) => {
 +                let tymut_string = tymut.to_string();
 +                if tymut_string == "_" ||         //unknown type name,
 +                   tymut_string.len() > 10 ||     //name longer than saying "reference",
 +                   region.to_string() != ""       //... or a complex type
 +                {
 +                    match tymut {
 +                        ty::TypeAndMut{mutbl, ..} => {
 +                            format!("{}reference", match mutbl {
 +                                hir::Mutability::MutMutable => "mutable ",
 +                                _ => ""
 +                            })
 +                        }
 +                    }
 +                } else {
 +                    format!("&{}", tymut_string)
 +                }
 +            }
              ty::TyFnDef(..) => format!("fn item"),
              ty::TyFnPtr(_) => "fn pointer".to_string(),
              ty::TyTrait(ref inner) => {
index d2ef3356afb9d69973c508ecb2924bca70b7ea7a,b3feac2bdc5e0c2b71d83caa9207ee8303b57e4f..8ae40e71bee58a6eac20fc76e55c66938aceab60
@@@ -9,7 -9,7 +9,7 @@@
  // except according to those terms.
  
  
- use rustc::ty::{FnOutput, TyCtxt};
+ use rustc::ty::TyCtxt;
  use rustc::mir::repr::*;
  use rustc::util::nodemap::FnvHashMap;
  use rustc_data_structures::indexed_vec::{Idx, IndexVec};
@@@ -231,8 -231,7 +231,7 @@@ impl<'tcx> Index<MovePathIndex> for Mov
      }
  }
  
- struct MovePathDataBuilder<'a, 'tcx: 'a> {
-     mir: &'a Mir<'tcx>,
+ struct MovePathDataBuilder<'tcx> {
      pre_move_paths: Vec<PreMovePath<'tcx>>,
      rev_lookup: MovePathLookup<'tcx>,
  }
@@@ -412,7 -411,7 +411,7 @@@ impl<'tcx> MovePathLookup<'tcx> 
      }
  }
  
- impl<'a, 'tcx> MovePathDataBuilder<'a, 'tcx> {
+ impl<'tcx> MovePathDataBuilder<'tcx> {
      fn lookup(&mut self, lval: &Lvalue<'tcx>) -> Lookup<MovePathIndex> {
          let proj = match *lval {
              Lvalue::Var(var_idx) =>
@@@ -528,7 -527,6 +527,6 @@@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tc
      // BlockContexts constructed on each iteration. (Moving is more
      // straight-forward than mutable borrows in this instance.)
      let mut builder = MovePathDataBuilder {
-         mir: mir,
          pre_move_paths: Vec::new(),
          rev_lookup: MovePathLookup::new(mir),
      };
                          Rvalue::InlineAsm { .. } => {}
                      }
                  }
 +                StatementKind::StorageLive(_) |
 +                StatementKind::StorageDead(_) => {}
                  StatementKind::SetDiscriminant{ .. } => {
                      span_bug!(stmt.source_info.span,
                                "SetDiscriminant should not exist during borrowck");
              TerminatorKind::Return => {
                  let source = Location { block: bb,
                                          index: bb_data.statements.len() };
-                 if let FnOutput::FnConverging(_) = bb_ctxt.builder.mir.return_ty {
-                     debug!("gather_moves Return on_move_out_lval return {:?}", source);
-                     bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source);
-                 } else {
-                     debug!("gather_moves Return on_move_out_lval \
-                             assuming unreachable return {:?}", source);
-                 }
+                 debug!("gather_moves Return on_move_out_lval return {:?}", source);
+                 bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source);
              }
  
              TerminatorKind::If { ref cond, targets: _ } => {
      }
  }
  
- struct BlockContext<'b, 'a: 'b, 'tcx: 'a> {
+ struct BlockContext<'b, 'tcx: 'b> {
      _tcx: TyCtxt<'b, 'tcx, 'tcx>,
      moves: &'b mut Vec<MoveOut>,
-     builder: MovePathDataBuilder<'a, 'tcx>,
+     builder: MovePathDataBuilder<'tcx>,
      path_map: &'b mut Vec<Vec<MoveOutIndex>>,
      loc_map_bb: &'b mut Vec<Vec<MoveOutIndex>>,
  }
  
- impl<'b, 'a: 'b, 'tcx: 'a> BlockContext<'b, 'a, 'tcx> {
+ impl<'b, 'tcx: 'b> BlockContext<'b, 'tcx> {
      fn on_move_out_lval(&mut self,
                          stmt_kind: StmtKind,
                          lval: &Lvalue<'tcx>,
index 20673dc1e181addb0148222acba2c7c3edec2d24,4049a2b815d0209ceb5ed91cb7f718e347e2061a..bf6ebcb5efefb6e02bc4fb86281082299b4b11fd
@@@ -215,7 -215,7 +215,7 @@@ fn check_expr(cx: &mut MatchCheckCtxt, 
              // Check for empty enum, because is_useful only works on inhabited types.
              let pat_ty = cx.tcx.node_id_to_type(scrut.id);
              if inlined_arms.is_empty() {
-                 if !pat_ty.is_empty(cx.tcx) {
+                 if !pat_ty.is_uninhabited(cx.tcx) {
                      // We know the type is inhabited, so this must be wrong
                      let mut err = struct_span_err!(cx.tcx.sess, ex.span, E0002,
                                                     "non-exhaustive patterns: type {} is non-empty",
                           possibly adding wildcards or more match arms.");
                      err.emit();
                  }
-                 // If the type *is* empty, it's vacuously exhaustive
+                 // If the type *is* uninhabited, it's vacuously exhaustive
                  return;
              }
  
@@@ -1175,10 -1175,8 +1175,10 @@@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> fo
                _: LoanCause) {
          match kind {
              MutBorrow => {
 -                span_err!(self.cx.tcx.sess, span, E0301,
 +                struct_span_err!(self.cx.tcx.sess, span, E0301,
                            "cannot mutably borrow in a pattern guard")
 +                    .span_label(span, &format!("borrowed mutably in pattern guard"))
 +                    .emit();
              }
              ImmBorrow | UniqueImmBorrow => {}
          }
      fn mutate(&mut self, _: NodeId, span: Span, _: cmt, mode: MutateMode) {
          match mode {
              MutateMode::JustWrite | MutateMode::WriteAndRead => {
 -                span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
 +                struct_span_err!(self.cx.tcx.sess, span, E0302, "cannot assign in a pattern guard")
 +                    .span_label(span, &format!("assignment in pattern guard"))
 +                    .emit();
              }
              MutateMode::Init => {}
          }
index 814d56f44ac30430b4a63035824b807b6c60a537,86c95db89c8a36538e6b2c1990ca370c577ba872..26eb782a73b0031c656e5353801828d421726502
@@@ -162,7 -162,7 +162,7 @@@ macro_rules! unpack 
  pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
                                         fn_id: ast::NodeId,
                                         arguments: A,
-                                        return_ty: ty::FnOutput<'gcx>,
+                                        return_ty: Ty<'gcx>,
                                         ast_block: &'gcx hir::Block)
                                         -> (Mir<'tcx>, ScopeAuxiliaryVec)
      where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
@@@ -238,8 -238,7 +238,8 @@@ pub fn construct_const<'a, 'gcx, 'tcx>(
      let span = tcx.map.span(item_id);
      let mut builder = Builder::new(hir, span);
  
 -    let extent = ROOT_CODE_EXTENT;
 +    let extent = tcx.region_maps.temporary_scope(ast_expr.id)
 +                    .unwrap_or(ROOT_CODE_EXTENT);
      let mut block = START_BLOCK;
      let _ = builder.in_scope(extent, block, |builder| {
          let expr = builder.hir.mirror(ast_expr);
      });
  
      let ty = tcx.expr_ty_adjusted(ast_expr);
-     builder.finish(vec![], IndexVec::new(), ty::FnConverging(ty))
+     builder.finish(vec![], IndexVec::new(), ty)
  }
  
  impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
      fn finish(self,
                upvar_decls: Vec<UpvarDecl>,
                arg_decls: IndexVec<Arg, ArgDecl<'tcx>>,
-               return_ty: ty::FnOutput<'tcx>)
+               return_ty: Ty<'tcx>)
                -> (Mir<'tcx>, ScopeAuxiliaryVec) {
          for (index, block) in self.cfg.basic_blocks.iter().enumerate() {
              if block.terminator.is_none() {
  
      fn args_and_body<A>(&mut self,
                          mut block: BasicBlock,
-                         return_ty: ty::FnOutput<'tcx>,
+                         return_ty: Ty<'tcx>,
                          arguments: A,
                          argument_extent: CodeExtent,
                          ast_block: &'gcx hir::Block)
          }
  
          // FIXME(#32959): temporary hack for the issue at hand
-         let return_is_unit = if let ty::FnConverging(t) = return_ty {
-             t.is_nil()
-         } else {
-             false
-         };
+         let return_is_unit = return_ty.is_nil();
          // start the first basic block and translate the body
          unpack!(block = self.ast_block(&Lvalue::ReturnPointer, return_is_unit, block, ast_block));
  
index 17dd85abd64e371a9fe0289ac668f09e7e51989a,aaa20405b8d57979be1bea46a1f4e03daa2c8c34..21b406c3bf5c99ba1e26d2822d62a3d356c1760e
@@@ -25,7 -25,7 +25,7 @@@
  use rustc::mir::repr::*;
  use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
  use rustc::mir::traversal::ReversePostorder;
- use rustc::ty::{self, TyCtxt};
+ use rustc::ty::TyCtxt;
  use syntax_pos::Span;
  
  use build::Location;
@@@ -87,12 -87,8 +87,12 @@@ impl<'tcx> Visitor<'tcx> for TempCollec
          if let Lvalue::Temp(index) = *lvalue {
              // Ignore drops, if the temp gets promoted,
              // then it's constant and thus drop is noop.
 -            if let LvalueContext::Drop = context {
 -                return;
 +            // Storage live ranges are also irrelevant.
 +            match context {
 +                LvalueContext::Drop |
 +                LvalueContext::StorageLive |
 +                LvalueContext::StorageDead => return,
 +                _ => {}
              }
  
              let temp = &mut self.temps[index];
@@@ -223,12 -219,12 +223,12 @@@ impl<'a, 'tcx> Promoter<'a, 'tcx> 
          let (mut rvalue, mut call) = (None, None);
          let source_info = if stmt_idx < no_stmts {
              let statement = &mut self.source[bb].statements[stmt_idx];
 -            let mut rhs = match statement.kind {
 +            let rhs = match statement.kind {
                  StatementKind::Assign(_, ref mut rhs) => rhs,
 -                StatementKind::SetDiscriminant{ .. } =>
 -                    span_bug!(statement.source_info.span,
 -                              "cannot promote SetDiscriminant {:?}",
 -                              statement),
 +                _ => {
 +                    span_bug!(statement.source_info.span, "{:?} is not an assignment",
 +                              statement);
 +                }
              };
              if self.keep_original {
                  rvalue = Some(rhs.clone());
          let span = self.promoted.span;
          let new_operand = Operand::Constant(Constant {
              span: span,
-             ty: self.promoted.return_ty.unwrap(),
+             ty: self.promoted.return_ty,
              literal: Literal::Promoted {
                  index: Promoted::new(self.source.promoted.len())
              }
                      StatementKind::Assign(_, ref mut rvalue) => {
                          mem::replace(rvalue, Rvalue::Use(new_operand))
                      }
 -                    StatementKind::SetDiscriminant{ .. } => {
 -                        span_bug!(statement.source_info.span,
 -                                  "cannot promote SetDiscriminant {:?}",
 -                                  statement);
 -                    }
 +                    _ => bug!()
                  }
              }
              Candidate::ShuffleIndices(bb) => {
@@@ -354,10 -354,8 +354,10 @@@ pub fn promote_candidates<'a, 'tcx>(mir
                  let statement = &mir[bb].statements[stmt_idx];
                  let dest = match statement.kind {
                      StatementKind::Assign(ref dest, _) => dest,
 -                    StatementKind::SetDiscriminant{ .. } =>
 -                        panic!("cannot promote SetDiscriminant"),
 +                    _ => {
 +                        span_bug!(statement.source_info.span,
 +                                  "expected assignment to promote");
 +                    }
                  };
                  if let Lvalue::Temp(index) = *dest {
                      if temps[index] == TempState::PromotedOut {
                      parent_scope: None
                  }).into_iter().collect(),
                  IndexVec::new(),
-                 ty::FnConverging(ty),
+                 ty,
                  IndexVec::new(),
                  IndexVec::new(),
                  IndexVec::new(),
      for block in mir.basic_blocks_mut() {
          block.statements.retain(|statement| {
              match statement.kind {
 -                StatementKind::Assign(Lvalue::Temp(index), _) => {
 +                StatementKind::Assign(Lvalue::Temp(index), _) |
 +                StatementKind::StorageLive(Lvalue::Temp(index)) |
 +                StatementKind::StorageDead(Lvalue::Temp(index)) => {
                      !promoted(index)
                  }
                  _ => true
index 87a10f1bb5bfc749fe808975fa699fb60d882d48,57c0f66448d358f12021e5b13d9772a48273b54f..103a15dadb61cfcc9481049a9eb28d804445bbb3
@@@ -416,7 -416,7 +416,7 @@@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx
              }
          }
  
-         let return_ty = mir.return_ty.unwrap();
+         let return_ty = mir.return_ty;
          self.qualif = self.return_qualif.unwrap_or(Qualif::NOT_CONST);
  
          match self.mode {
@@@ -854,17 -854,7 +854,17 @@@ impl<'a, 'tcx> Visitor<'tcx> for Qualif
  
      fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) {
          assert_eq!(self.location.block, bb);
 -        self.nest(|this| this.super_statement(bb, statement));
 +        self.nest(|this| {
 +            this.visit_source_info(&statement.source_info);
 +            match statement.kind {
 +                StatementKind::Assign(ref lvalue, ref rvalue) => {
 +                    this.visit_assign(bb, lvalue, rvalue);
 +                }
 +                StatementKind::SetDiscriminant { .. } |
 +                StatementKind::StorageLive(_) |
 +                StatementKind::StorageDead(_) => {}
 +            }
 +        });
          self.location.statement_index += 1;
      }
  
@@@ -1001,7 -991,7 +1001,7 @@@ impl<'tcx> MirMapPass<'tcx> for Qualify
  
              // Statics must be Sync.
              if mode == Mode::Static {
-                 let ty = mir.return_ty.unwrap();
+                 let ty = mir.return_ty;
                  tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
                      let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
                      let mut fulfillment_cx = traits::FulfillmentContext::new();
index 79e31167f2f7f5b542bb35b8623b8aed9986701a,a030ba17655fd908f47f27364bddb4e7b367e4c9..bbd2a93659b0aff480d70a5ba03d7113c597083c
@@@ -85,9 -85,7 +85,7 @@@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> 
      }
  
      fn visit_mir(&mut self, mir: &Mir<'tcx>) {
-         if let ty::FnConverging(t) = mir.return_ty {
-             self.sanitize_type(&"return type", t);
-         }
+         self.sanitize_type(&"return type", mir.return_ty);
          for var_decl in &mir.var_decls {
              self.sanitize_type(var_decl, var_decl.ty);
          }
@@@ -135,14 -133,7 +133,7 @@@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'
              Lvalue::Static(def_id) =>
                  LvalueTy::Ty { ty: self.tcx().lookup_item_type(def_id).ty },
              Lvalue::ReturnPointer => {
-                 if let ty::FnConverging(return_ty) = self.mir.return_ty {
-                     LvalueTy::Ty { ty: return_ty }
-                 } else {
-                     LvalueTy::Ty {
-                         ty: span_mirbug_and_err!(
-                             self, lvalue, "return in diverging function")
-                     }
-                 }
+                 LvalueTy::Ty { ty: self.mir.return_ty }
              }
              Lvalue::Projection(ref proj) => {
                  let base_ty = self.sanitize_lvalue(&proj.base);
@@@ -382,15 -373,6 +373,15 @@@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'g
                                 variant_index);
                  };
              }
 +            StatementKind::StorageLive(ref lv) |
 +            StatementKind::StorageDead(ref lv) => {
 +                match *lv {
 +                    Lvalue::Temp(_) | Lvalue::Var(_) => {}
 +                    _ => {
 +                        span_mirbug!(self, stmt, "bad lvalue: expected temp or var");
 +                    }
 +                }
 +            }
          }
      }
  
                         sig: &ty::FnSig<'tcx>,
                         destination: &Option<(Lvalue<'tcx>, BasicBlock)>) {
          let tcx = self.tcx();
-         match (destination, sig.output) {
-             (&Some(..), ty::FnDiverging) => {
-                 span_mirbug!(self, term, "call to diverging function {:?} with dest", sig);
-             }
-             (&Some((ref dest, _)), ty::FnConverging(ty)) => {
+         match *destination {
+             Some((ref dest, _)) => {
                  let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
-                 if let Err(terr) = self.sub_types(self.last_span, ty, dest_ty) {
+                 if let Err(terr) = self.sub_types(self.last_span, sig.output, dest_ty) {
                      span_mirbug!(self, term,
                                   "call dest mismatch ({:?} <- {:?}): {:?}",
-                                  dest_ty, ty, terr);
+                                  dest_ty, sig.output, terr);
                  }
-             }
-             (&None, ty::FnDiverging) => {}
-             (&None, ty::FnConverging(..)) => {
-                 span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
-              }
+             },
+             None => {
+                 // FIXME(canndrew): This is_never should probably be an is_uninhabited
+                 if !sig.output.is_never() {
+                     span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
+                 }
+             },
          }
      }
  
index d8f39358411a19ef181adb25129038766bc1183a,42239a7d5a4eea216c93e2332edcec215f134a47..de9ddcd934216e4cbcecf16de4c0cbdffc8a6d05
@@@ -440,7 -440,7 +440,7 @@@ impl<'a, 'tcx, 'v> Visitor<'v> for Priv
                      let expr_ty = self.tcx.expr_ty(expr);
                      let def = match expr_ty.sty {
                          ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
-                             output: ty::FnConverging(ty), ..
+                             output: ty, ..
                          }), ..}) => ty,
                          _ => expr_ty
                      }.ty_adt_def().unwrap();
@@@ -938,8 -938,7 +938,8 @@@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for 
                                  self.tcx.sess.add_lint(lint::builtin::PRIVATE_IN_PUBLIC,
                                                         node_id,
                                                         ty.span,
 -                                                       format!("private type in public interface"));
 +                                                       format!("private type in public \
 +                                                                interface (error E0446)"));
                              }
                          }
                      }
index 30618ff37273569ba6251f5780d76ae3dae1ad51,70c3fdc269d682cc4143907ae0a4fad6e17ecac1..c78cda75e820e548d5a585c1b5e2d1736745f3d0
@@@ -1972,7 -1972,7 +1972,7 @@@ pub fn trans_named_tuple_constructor<'b
  
      let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig());
      let sig = ccx.tcx().normalize_associated_type(&sig);
-     let result_ty = sig.output.unwrap();
+     let result_ty = sig.output;
  
      // Get location to store the result. If the user does not care about
      // the result, just make a stack slot
@@@ -2054,7 -2054,7 +2054,7 @@@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &
      if !fcx.fn_ty.ret.is_ignore() {
          let dest = fcx.get_ret_slot(bcx, "eret_slot");
          let dest_val = adt::MaybeSizedValue::sized(dest); // Can return unsized value
-         let repr = adt::represent_type(ccx, sig.output.unwrap());
+         let repr = adt::represent_type(ccx, sig.output);
          let mut llarg_idx = fcx.fn_ty.ret.is_indirect() as usize;
          let mut arg_idx = 0;
          for (i, arg_ty) in sig.inputs.into_iter().enumerate() {
@@@ -2250,17 -2250,10 +2250,17 @@@ fn write_metadata(cx: &SharedCrateConte
      };
      unsafe {
          llvm::LLVMSetInitializer(llglobal, llconst);
 -        let name =
 +        let section_name =
              cx.tcx().sess.cstore.metadata_section_name(&cx.sess().target.target);
 -        let name = CString::new(name).unwrap();
 -        llvm::LLVMSetSection(llglobal, name.as_ptr())
 +        let name = CString::new(section_name).unwrap();
 +        llvm::LLVMSetSection(llglobal, name.as_ptr());
 +
 +        // Also generate a .section directive to force no
 +        // flags, at least for ELF outputs, so that the
 +        // metadata doesn't get loaded into memory.
 +        let directive = format!(".section {}", section_name);
 +        let directive = CString::new(directive).unwrap();
 +        llvm::LLVMSetModuleInlineAsm(cx.metadata_llmod(), directive.as_ptr())
      }
      return metadata;
  }
@@@ -2576,7 -2569,7 +2576,7 @@@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtx
      assert_module_sources::assert_module_sources(tcx, &modules);
  
      // Skip crate items and just output metadata in -Z no-trans mode.
 -    if tcx.sess.opts.no_trans {
 +    if tcx.sess.opts.debugging_opts.no_trans {
          let linker_info = LinkerInfo::new(&shared_ccx, &[]);
          return CrateTranslation {
              modules: modules,
index 794da0d1473bd12b900d0aad7d842074f52c2dc8,6decc48c36a3b17a71586a42fa752b5990f18478..acc302430aee68383513650f15f2db85cf1b3aa2
@@@ -202,11 -202,10 +202,11 @@@ use rustc::mir::repr as mir
  use rustc::mir::visit as mir_visit;
  use rustc::mir::visit::Visitor as MirVisitor;
  
 +use rustc_const_eval as const_eval;
 +
  use syntax::abi::Abi;
  use errors;
  use syntax_pos::DUMMY_SP;
 -use syntax::ast::NodeId;
  use base::custom_coerce_unsize_info;
  use context::SharedCrateContext;
  use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized};
@@@ -544,46 -543,9 +544,46 @@@ impl<'a, 'tcx> MirVisitor<'tcx> for Mir
          debug!("visiting operand {:?}", *operand);
  
          let callee = match *operand {
 -            mir::Operand::Constant(mir::Constant { ty: &ty::TyS {
 -                sty: ty::TyFnDef(def_id, substs, _), ..
 -            }, .. }) => Some((def_id, substs)),
 +            mir::Operand::Constant(ref constant) => {
 +                if let ty::TyFnDef(def_id, substs, _) = constant.ty.sty {
 +                    // This is something that can act as a callee, proceed
 +                    Some((def_id, substs))
 +                } else {
 +                    // This is not a callee, but we still have to look for
 +                    // references to `const` items
 +                    if let mir::Literal::Item { def_id, substs } = constant.literal {
 +                        let tcx = self.scx.tcx();
 +                        let substs = monomorphize::apply_param_substs(tcx,
 +                                                                      self.param_substs,
 +                                                                      &substs);
 +
 +                        // If the constant referred to here is an associated
 +                        // item of a trait, we need to resolve it to the actual
 +                        // constant in the corresponding impl. Luckily
 +                        // const_eval::lookup_const_by_id() does that for us.
 +                        if let Some((expr, _)) = const_eval::lookup_const_by_id(tcx,
 +                                                                                def_id,
 +                                                                                Some(substs)) {
 +                            // The hir::Expr we get here is the initializer of
 +                            // the constant, what we really want is the item
 +                            // DefId.
 +                            let const_node_id = tcx.map.get_parent(expr.id);
 +                            let def_id = if tcx.map.is_inlined_node_id(const_node_id) {
 +                                tcx.sess.cstore.defid_for_inlined_node(const_node_id).unwrap()
 +                            } else {
 +                                tcx.map.local_def_id(const_node_id)
 +                            };
 +
 +                            collect_const_item_neighbours(self.scx,
 +                                                          def_id,
 +                                                          substs,
 +                                                          self.output);
 +                        }
 +                    }
 +
 +                    None
 +                }
 +            }
              _ => None
          };
  
@@@ -791,6 -753,7 +791,7 @@@ fn find_drop_glue_neighbors<'a, 'tcx>(s
          ty::TyRef(..)   |
          ty::TyFnDef(..) |
          ty::TyFnPtr(_)  |
+         ty::TyNever     |
          ty::TyTrait(_)  => {
              /* nothing to do */
          }
@@@ -1155,8 -1118,10 +1156,8 @@@ impl<'b, 'a, 'v> hir_visit::Visitor<'v
                  self.output.push(TransItem::Static(item.id));
              }
              hir::ItemConst(..) => {
 -                debug!("RootCollector: ItemConst({})",
 -                       def_id_to_string(self.scx.tcx(),
 -                                        self.scx.tcx().map.local_def_id(item.id)));
 -                add_roots_for_const_item(self.scx, item.id, self.output);
 +                // const items only generate translation items if they are
 +                // actually used somewhere. Just declaring them is insufficient.
              }
              hir::ItemFn(_, _, _, _, ref generics, _) => {
                  if !generics.is_type_parameterized() {
@@@ -1280,21 -1245,23 +1281,21 @@@ fn create_trans_items_for_default_impls
  // There are no translation items for constants themselves but their
  // initializers might still contain something that produces translation items,
  // such as cast that introduce a new vtable.
 -fn add_roots_for_const_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 -                                      const_item_node_id: NodeId,
 -                                      output: &mut Vec<TransItem<'tcx>>)
 +fn collect_const_item_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 +                                           def_id: DefId,
 +                                           substs: &'tcx Substs<'tcx>,
 +                                           output: &mut Vec<TransItem<'tcx>>)
  {
 -    let def_id = scx.tcx().map.local_def_id(const_item_node_id);
 -
      // Scan the MIR in order to find function calls, closures, and
      // drop-glue
      let mir = errors::expect(scx.sess().diagnostic(), scx.get_mir(def_id),
          || format!("Could not find MIR for const: {:?}", def_id));
  
 -    let empty_substs = scx.empty_substs_for_def_id(def_id);
      let visitor = MirNeighborCollector {
          scx: scx,
          mir: &mir,
          output: output,
 -        param_substs: empty_substs
 +        param_substs: substs
      };
  
      visit_mir_and_promoted(visitor, &mir);
index de5581af2912d2edda55462de68b85f8d4ab6026,784e4a32f9469df9a096605a5c128491d3c69f14..e0d959f4774a64e3a2952f85bb6dcf081f931025
@@@ -19,6 -19,7 +19,7 @@@ use rustc::mir::visit::{Visitor, Lvalue
  use rustc::mir::traversal;
  use common::{self, Block, BlockAndBuilder};
  use glue;
+ use std::iter;
  use super::rvalue;
  
  pub fn lvalue_locals<'bcx, 'tcx>(bcx: Block<'bcx,'tcx>,
@@@ -31,7 -32,7 +32,7 @@@
      let local_types = mir.arg_decls.iter().map(|a| a.ty)
                 .chain(mir.var_decls.iter().map(|v| v.ty))
                 .chain(mir.temp_decls.iter().map(|t| t.ty))
-                .chain(mir.return_ty.maybe_converging());
+                .chain(iter::once(mir.return_ty));
      for (index, ty) in local_types.enumerate() {
          let ty = bcx.monomorphize(&ty);
          debug!("local {} has type {:?}", index, ty);
@@@ -161,11 -162,8 +162,11 @@@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> fo
                  LvalueContext::Call => {
                      self.mark_assigned(index);
                  }
 -                LvalueContext::Consume => {
 -                }
 +
 +                LvalueContext::StorageLive |
 +                LvalueContext::StorageDead |
 +                LvalueContext::Consume => {}
 +
                  LvalueContext::Store |
                  LvalueContext::Inspect |
                  LvalueContext::Borrow { .. } |
                  LvalueContext::Projection => {
                      self.mark_as_lvalue(index);
                  }
 +
                  LvalueContext::Drop => {
                      let ty = lvalue.ty(self.mir, self.bcx.tcx());
                      let ty = self.bcx.monomorphize(&ty.to_ty(self.bcx.tcx()));
index 084bbff338346e72440513840f729ebbcae09f81,ddc8c82c122549e0c80079c535019b3a8449a3cd..4334f043772e361962a409b94e1ec0e7c6a82a0c
@@@ -30,8 -30,8 +30,8 @@@ fn equate_intrinsic_type<'a, 'tcx>(ccx
                                     it: &hir::ForeignItem,
                                     n_tps: usize,
                                     abi: Abi,
-                                    inputs: Vec<ty::Ty<'tcx>>,
-                                    output: ty::FnOutput<'tcx>) {
+                                    inputs: Vec<Ty<'tcx>>,
+                                    output: Ty<'tcx>) {
      let tcx = ccx.tcx;
      let def_id = tcx.map.local_def_id(it.id);
      let i_ty = tcx.lookup_item_type(def_id);
      }));
      let i_n_tps = i_ty.generics.types.len(subst::FnSpace);
      if i_n_tps != n_tps {
 -        span_err!(tcx.sess, it.span, E0094,
 +        struct_span_err!(tcx.sess, it.span, E0094,
              "intrinsic has wrong number of type \
               parameters: found {}, expected {}",
 -             i_n_tps, n_tps);
 +             i_n_tps, n_tps)
 +             .span_label(it.span, &format!("expected {} type parameter", n_tps))
 +             .emit();
      } else {
          require_same_types(ccx,
                             TypeOrigin::IntrinsicType(it.span),
@@@ -106,9 -104,9 +106,9 @@@ pub fn check_intrinsic_type(ccx: &Crate
                  return;
              }
          };
-         (n_tps, inputs, ty::FnConverging(output))
+         (n_tps, inputs, output)
      } else if &name[..] == "abort" || &name[..] == "unreachable" {
-         (0, Vec::new(), ty::FnDiverging)
+         (0, Vec::new(), tcx.types.never)
      } else {
          let (n_tps, inputs, output) = match &name[..] {
              "breakpoint" => (0, Vec::new(), tcx.mk_nil()),
                      abi: Abi::Rust,
                      sig: ty::Binder(FnSig {
                          inputs: vec![mut_u8],
-                         output: ty::FnOutput::FnConverging(tcx.mk_nil()),
+                         output: tcx.mk_nil(),
                          variadic: false,
                      }),
                  });
                  return;
              }
          };
-         (n_tps, inputs, ty::FnConverging(output))
+         (n_tps, inputs, output)
      };
      equate_intrinsic_type(ccx, it, n_tps, Abi::RustIntrinsic, inputs, output)
  }
@@@ -379,7 -377,7 +379,7 @@@ pub fn check_platform_intrinsic_type(cc
                      }
                      match_intrinsic_type_to_type(ccx, "return value", it.span,
                                                   &mut structural_to_nomimal,
-                                                  &intr.output, sig.output.unwrap());
+                                                  &intr.output, sig.output);
                      return
                  }
                  None => {
      };
  
      equate_intrinsic_type(ccx, it, n_tps, Abi::PlatformIntrinsic,
-                           inputs, ty::FnConverging(output))
+                           inputs, output)
  }
  
  // walk the expected type and the actual type in lock step, checking they're
index e99a95e4135196402f67893163a191e7d8ca79db,8e0f3082bae7a5853a7256ca13021f6fea429f71..d985d3ccbea89751909d018202a7cc999f6086df
@@@ -372,7 -372,7 +372,7 @@@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 't
      // expects the types within the function to be consistent.
      err_count_on_creation: usize,
  
-     ret_ty: ty::FnOutput<'tcx>,
+     ret_ty: Ty<'tcx>,
  
      ps: RefCell<UnsafetyState>,
  
@@@ -676,14 -676,9 +676,9 @@@ fn check_fn<'a, 'gcx, 'tcx>(inherited: 
      let mut fcx = FnCtxt::new(inherited, fn_sig.output, body.id);
      *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
  
-     fn_sig.output = match fcx.ret_ty {
-         ty::FnConverging(orig_ret_ty) => {
-             fcx.require_type_is_sized(orig_ret_ty, decl.output.span(), traits::ReturnType);
-             ty::FnConverging(fcx.instantiate_anon_types(&orig_ret_ty))
-         }
-         ty::FnDiverging => ty::FnDiverging
-     };
-     fcx.ret_ty = fn_sig.output;
+     fcx.require_type_is_sized(fcx.ret_ty, decl.output.span(), traits::ReturnType);
+     fcx.ret_ty = fcx.instantiate_anon_types(&fcx.ret_ty);
+     fn_sig.output = fcx.ret_ty;
  
      {
          let mut visit = GatherLocalsVisitor { fcx: &fcx, };
  
      inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
  
-     fcx.check_block_with_expected(body, match fcx.ret_ty {
-         ty::FnConverging(result_type) => ExpectHasType(result_type),
-         ty::FnDiverging => NoExpectation
-     });
+     fcx.check_block_with_expected(body, ExpectHasType(fcx.ret_ty));
  
      fcx
  }
@@@ -1168,7 -1160,7 +1160,7 @@@ fn check_const_with_type<'a, 'tcx>(ccx
                                     expected_type: Ty<'tcx>,
                                     id: ast::NodeId) {
      ccx.inherited(id).enter(|inh| {
-         let fcx = FnCtxt::new(&inh, ty::FnConverging(expected_type), expr.id);
+         let fcx = FnCtxt::new(&inh, expected_type, expr.id);
          fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
  
          // Gather locals in statics (because of block expressions).
@@@ -1465,7 -1457,7 +1457,7 @@@ enum TupleArgumentsFlag 
  
  impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
      pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
-                rty: ty::FnOutput<'tcx>,
+                rty: Ty<'tcx>,
                 body_id: ast::NodeId)
                 -> FnCtxt<'a, 'gcx, 'tcx> {
          FnCtxt {
          debug!("write_ty({}, {:?}) in fcx {}",
                 node_id, ty, self.tag());
          self.tables.borrow_mut().node_types.insert(node_id, ty);
+         // Add adjustments to !-expressions
+         if ty.is_never() {
+             if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(node_id) {
+                 let adj = adjustment::AdjustNeverToAny(self.next_diverging_ty_var());
+                 self.write_adjustment(node_id, adj);
+             }
+         }
      }
  
      pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
          let mut type_scheme = self.tcx.lookup_item_type(did);
          if type_scheme.ty.is_fn() {
              // Tuple variants have fn type even in type namespace, extract true variant type from it
-             let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap().unwrap();
+             let fn_ret = self.tcx.no_late_bound_regions(&type_scheme.ty.fn_ret()).unwrap();
              type_scheme = ty::TypeScheme { ty: fn_ret, generics: type_scheme.generics }
          }
          let type_predicates = self.tcx.lookup_predicates(did);
      pub fn write_nil(&self, node_id: ast::NodeId) {
          self.write_ty(node_id, self.tcx.mk_nil());
      }
+     pub fn write_never(&self, node_id: ast::NodeId) {
+         self.write_ty(node_id, self.tcx.types.never);
+     }
      pub fn write_error(&self, node_id: ast::NodeId) {
          self.write_ty(node_id, self.tcx.types.err);
      }
      }
  
      pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> {
+         if let Some(&adjustment::AdjustNeverToAny(ref t))
+                 = self.tables.borrow().adjustments.get(&ex.id) {
+             return t;
+         }
          match self.tables.borrow().node_types.get(&ex.id) {
              Some(&t) => t,
              None => {
          for ty in &self.unsolved_variables() {
              let resolved = self.resolve_type_vars_if_possible(ty);
              if self.type_var_diverges(resolved) {
-                 debug!("default_type_parameters: defaulting `{:?}` to `()` because it diverges",
+                 debug!("default_type_parameters: defaulting `{:?}` to `!` because it diverges",
                         resolved);
-                 self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                 self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
+                                    self.tcx.mk_diverging_default());
              } else {
                  match self.type_is_unconstrained_numeric(resolved) {
                      UnconstrainedInt => {
              for ty in &unsolved_variables {
                  let resolved = self.resolve_type_vars_if_possible(ty);
                  if self.type_var_diverges(resolved) {
-                     self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                     self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
+                                        self.tcx.mk_diverging_default());
                  } else {
                      match self.type_is_unconstrained_numeric(resolved) {
                          UnconstrainedInt | UnconstrainedFloat => {
              let _ = self.commit_if_ok(|_: &infer::CombinedSnapshot| {
                  for ty in &unbound_tyvars {
                      if self.type_var_diverges(ty) {
-                         self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                         self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
+                                            self.tcx.mk_diverging_default());
                      } else {
                          match self.type_is_unconstrained_numeric(ty) {
                              UnconstrainedInt => {
          // reporting for more then one conflict.
          for ty in &unbound_tyvars {
              if self.type_var_diverges(ty) {
-                 self.demand_eqtype(syntax_pos::DUMMY_SP, *ty, self.tcx.mk_nil());
+                 self.demand_eqtype(syntax_pos::DUMMY_SP, *ty,
+                                    self.tcx.mk_diverging_default());
              } else {
                  match self.type_is_unconstrained_numeric(ty) {
                      UnconstrainedInt => {
          // extract method return type, which will be &T;
          // all LB regions should have been instantiated during method lookup
          let ret_ty = method.ty.fn_ret();
-         let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap();
+         let ret_ty = self.tcx.no_late_bound_regions(&ret_ty).unwrap();
  
          // method returns &T, but the type as visible to user is T, so deref
          ret_ty.builtin_deref(true, NoPreference).unwrap()
                                     args_no_rcvr: &'gcx [P<hir::Expr>],
                                     tuple_arguments: TupleArgumentsFlag,
                                     expected: Expectation<'tcx>)
-                                    -> ty::FnOutput<'tcx> {
+                                    -> Ty<'tcx> {
          if method_fn_ty.references_error() {
              let err_inputs = self.err_args(args_no_rcvr.len());
  
  
              self.check_argument_types(sp, &err_inputs[..], &[], args_no_rcvr,
                                        false, tuple_arguments);
-             ty::FnConverging(self.tcx.types.err)
+             self.tcx.types.err
          } else {
              match method_fn_ty.sty {
                  ty::TyFnDef(_, _, ref fty) => {
                  }
  
                  if let Some(&arg_ty) = self.tables.borrow().node_types.get(&arg.id) {
-                     any_diverges = any_diverges || self.type_var_diverges(arg_ty);
+                     // FIXME(canndrew): This is_never should probably be an is_uninhabited
+                     any_diverges = any_diverges ||
+                                    self.type_var_diverges(arg_ty) ||
+                                    arg_ty.is_never();
                  }
              }
              if any_diverges && !warned {
  
      fn write_call(&self,
                    call_expr: &hir::Expr,
-                   output: ty::FnOutput<'tcx>) {
-         self.write_ty(call_expr.id, match output {
-             ty::FnConverging(output_ty) => output_ty,
-             ty::FnDiverging => self.next_diverging_ty_var()
-         });
+                   output: Ty<'tcx>) {
+         self.write_ty(call_expr.id, output);
      }
  
      // AST fragment checking
      fn expected_types_for_fn_args(&self,
                                    call_span: Span,
                                    expected_ret: Expectation<'tcx>,
-                                   formal_ret: ty::FnOutput<'tcx>,
+                                   formal_ret: Ty<'tcx>,
                                    formal_args: &[Ty<'tcx>])
                                    -> Vec<Ty<'tcx>> {
          let expected_args = expected_ret.only_has_type(self).and_then(|ret_ty| {
-             if let ty::FnConverging(formal_ret_ty) = formal_ret {
-                 self.commit_regions_if_ok(|| {
-                     // Attempt to apply a subtyping relationship between the formal
-                     // return type (likely containing type variables if the function
-                     // is polymorphic) and the expected return type.
-                     // No argument expectations are produced if unification fails.
-                     let origin = TypeOrigin::Misc(call_span);
-                     let ures = self.sub_types(false, origin, formal_ret_ty, ret_ty);
-                     // FIXME(#15760) can't use try! here, FromError doesn't default
-                     // to identity so the resulting type is not constrained.
-                     match ures {
-                         // FIXME(#32730) propagate obligations
-                         Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
-                         Err(e) => return Err(e),
-                     }
-                     // Record all the argument types, with the substitutions
-                     // produced from the above subtyping unification.
-                     Ok(formal_args.iter().map(|ty| {
-                         self.resolve_type_vars_if_possible(ty)
-                     }).collect())
-                 }).ok()
-             } else {
-                 None
-             }
+             self.commit_regions_if_ok(|| {
+                 // Attempt to apply a subtyping relationship between the formal
+                 // return type (likely containing type variables if the function
+                 // is polymorphic) and the expected return type.
+                 // No argument expectations are produced if unification fails.
+                 let origin = TypeOrigin::Misc(call_span);
+                 let ures = self.sub_types(false, origin, formal_ret, ret_ty);
+                 // FIXME(#15760) can't use try! here, FromError doesn't default
+                 // to identity so the resulting type is not constrained.
+                 match ures {
+                     // FIXME(#32730) propagate obligations
+                     Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
+                     Err(e) => return Err(e),
+                 }
+                 // Record all the argument types, with the substitutions
+                 // produced from the above subtyping unification.
+                 Ok(formal_args.iter().map(|ty| {
+                     self.resolve_type_vars_if_possible(ty)
+                 }).collect())
+             }).ok()
          }).unwrap_or(vec![]);
          debug!("expected_types_for_fn_args(formal={:?} -> {:?}, expected={:?} -> {:?})",
                 formal_args, formal_ret,
                }
                self.write_nil(id);
            }
-           hir::ExprBreak(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
-           hir::ExprAgain(_) => { self.write_ty(id, self.next_diverging_ty_var()); }
+           hir::ExprBreak(_) => { self.write_never(id); }
+           hir::ExprAgain(_) => { self.write_never(id); }
            hir::ExprRet(ref expr_opt) => {
-             match self.ret_ty {
-                 ty::FnConverging(result_type) => {
-                     if let Some(ref e) = *expr_opt {
-                         self.check_expr_coercable_to_type(&e, result_type);
-                     } else {
-                         let eq_result = self.eq_types(false,
-                                                       TypeOrigin::Misc(expr.span),
-                                                       result_type,
-                                                       tcx.mk_nil())
-                             // FIXME(#32730) propagate obligations
-                             .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()));
-                         if eq_result.is_err() {
-                             struct_span_err!(tcx.sess, expr.span, E0069,
-                                      "`return;` in a function whose return type is not `()`")
-                                 .span_label(expr.span, &format!("return type is not ()"))
-                                 .emit();
-                         }
-                     }
-                 }
-                 ty::FnDiverging => {
-                     if let Some(ref e) = *expr_opt {
-                         self.check_expr(&e);
-                     }
-                     struct_span_err!(tcx.sess, expr.span, E0166,
-                         "`return` in a function declared as diverging")
-                         .span_label(expr.span, &format!("diverging function cannot return"))
+             if let Some(ref e) = *expr_opt {
+                 self.check_expr_coercable_to_type(&e, self.ret_ty);
+             } else {
+                 let eq_result = self.eq_types(false,
+                                               TypeOrigin::Misc(expr.span),
+                                               self.ret_ty,
+                                               tcx.mk_nil())
+                     // FIXME(#32730) propagate obligations
+                     .map(|InferOk { obligations, .. }| assert!(obligations.is_empty()));
+                 if eq_result.is_err() {
+                     struct_span_err!(tcx.sess, expr.span, E0069,
+                              "`return;` in a function whose return type is not `()`")
+                         .span_label(expr.span, &format!("return type is not ()"))
                          .emit();
                  }
              }
-             self.write_ty(id, self.next_diverging_ty_var());
+             self.write_never(id);
            }
            hir::ExprAssign(ref lhs, ref rhs) => {
              self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
  
              let tcx = self.tcx;
              if !tcx.expr_is_lval(&lhs) {
 -                span_err!(tcx.sess, expr.span, E0070,
 -                    "invalid left-hand side expression");
 +                struct_span_err!(
 +                    tcx.sess, expr.span, E0070,
 +                    "invalid left-hand side expression")
 +                .span_label(
 +                    expr.span,
 +                    &format!("left-hand of expression not valid"))
 +                .emit();
              }
  
              let lhs_ty = self.expr_ty(&lhs);
            hir::ExprLoop(ref body, _) => {
              self.check_block_no_value(&body);
              if !may_break(tcx, expr.id, &body) {
-                 self.write_ty(id, self.next_diverging_ty_var());
+                 self.write_never(id);
              } else {
                  self.write_nil(id);
              }
                                "unreachable statement".to_string());
                  warned = true;
              }
-             any_diverges = any_diverges || self.type_var_diverges(s_ty);
+             // FIXME(canndrew): This is_never should probably be an is_uninhabited
+             any_diverges = any_diverges ||
+                            self.type_var_diverges(s_ty) ||
+                            s_ty.is_never();
              any_err = any_err || s_ty.references_error();
          }
          match blk.expr {
index cdca988084cceb201332bcdae430a1da96850a7c,16fe1f718b921a3bb71b885c35c748055181cd56..a8b1683f6d354e1dce9bd28185f0bd6e7e4224c8
@@@ -41,13 -41,7 +41,13 @@@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, '
  
          let tcx = self.tcx;
          if !tcx.expr_is_lval(lhs_expr) {
 -            span_err!(tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression");
 +            struct_span_err!(
 +                tcx.sess, lhs_expr.span,
 +                E0067, "invalid left-hand side expression")
 +            .span_label(
 +                lhs_expr.span,
 +                &format!("invalid expression for left-hand side"))
 +            .emit();
          }
      }
  
                  // extract return type for method; all late bound regions
                  // should have been instantiated by now
                  let ret_ty = method_ty.fn_ret();
-                 Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap().unwrap())
+                 Ok(self.tcx.no_late_bound_regions(&ret_ty).unwrap())
              }
              None => {
                  Err(())
index a6f0e0ca31e3e4fa94dec928990daab430ac29df,77fd264b01d338fcbdfec5a13c1171b9d9038093..d94bfe7dcbdac2df758c55f87ec3256c1b9ee523
@@@ -284,7 -284,10 +284,10 @@@ declare_features! 
  
      // Allows tuple structs and variants in more contexts,
      // Permits numeric fields in struct expressions and patterns.
-     (active, relaxed_adts, "1.12.0", Some(35626))
+     (active, relaxed_adts, "1.12.0", Some(35626)),
+     // The `!` type
+     (active, never_type, "1.13.0", Some(35121))
  );
  
  declare_features! (
@@@ -314,7 -317,7 +317,7 @@@ declare_features! 
      (accepted, issue_5723_bootstrap, "1.0.0", None),
      (accepted, macro_rules, "1.0.0", None),
      // Allows using #![no_std]
 -    (accepted, no_std, "1.0.0", None),
 +    (accepted, no_std, "1.6.0", None),
      (accepted, slicing_syntax, "1.0.0", None),
      (accepted, struct_variant, "1.0.0", None),
      // These are used to test this portion of the compiler, they don't actually
@@@ -963,11 -966,25 +966,25 @@@ impl<'a> Visitor for PostExpansionVisit
                  gate_feature_post!(&self, conservative_impl_trait, ty.span,
                                     "`impl Trait` is experimental");
              }
+             ast::TyKind::Never => {
+                 gate_feature_post!(&self, never_type, ty.span,
+                                    "The `!` type is experimental");
+             },
              _ => {}
          }
          visit::walk_ty(self, ty)
      }
  
+     fn visit_fn_ret_ty(&mut self, ret_ty: &ast::FunctionRetTy) {
+         if let ast::FunctionRetTy::Ty(ref output_ty) = *ret_ty {
+             match output_ty.node {
+                 ast::TyKind::Never => return,
+                 _ => (),
+             };
+             self.visit_ty(output_ty)
+         }
+     }
      fn visit_expr(&mut self, e: &ast::Expr) {
          match e.node {
              ast::ExprKind::Box(_) => {
@@@ -1194,7 -1211,7 +1211,7 @@@ pub fn check_crate(krate: &ast::Crate
      visit::walk_crate(&mut PostExpansionVisitor { context: &ctx }, krate);
  }
  
 -#[derive(Clone, Copy)]
 +#[derive(Clone, Copy, PartialEq, Eq, Hash)]
  pub enum UnstableFeatures {
      /// Hard errors for unstable features are active, as on
      /// beta/stable channels.
index e174f3ad08d6adb4ef916d5a9f85bdb1ac65a27b,118096d9d4863fe39e745e98d876313d3c0b8492..126e8816d055924d3faf250ed32a4c840efdc68f
@@@ -1332,11 -1332,7 +1332,7 @@@ impl<'a> Parser<'a> 
      /// Parse optional return type [ -> TY ] in function decl
      pub fn parse_ret_ty(&mut self) -> PResult<'a, FunctionRetTy> {
          if self.eat(&token::RArrow) {
-             if self.eat(&token::Not) {
-                 Ok(FunctionRetTy::None(self.last_span))
-             } else {
-                 Ok(FunctionRetTy::Ty(self.parse_ty()?))
-             }
+             Ok(FunctionRetTy::Ty(self.parse_ty()?))
          } else {
              let pos = self.span.lo;
              Ok(FunctionRetTy::Default(mk_sp(pos, pos)))
              } else {
                  TyKind::Tup(ts)
              }
+         } else if self.eat(&token::Not) {
+             TyKind::Never
          } else if self.check(&token::BinOp(token::Star)) {
              // STAR POINTER (bare pointer?)
              self.bump();
      }
  
      /// Parse a structure field
 -    fn parse_name_and_ty(&mut self, pr: Visibility,
 -                         attrs: Vec<Attribute> ) -> PResult<'a, StructField> {
 -        let lo = match pr {
 -            Visibility::Inherited => self.span.lo,
 -            _ => self.last_span.lo,
 -        };
 +    fn parse_name_and_ty(&mut self,
 +                         lo: BytePos,
 +                         vis: Visibility,
 +                         attrs: Vec<Attribute>)
 +                         -> PResult<'a, StructField> {
          let name = self.parse_ident()?;
          self.expect(&token::Colon)?;
          let ty = self.parse_ty_sum()?;
          Ok(StructField {
              span: mk_sp(lo, self.last_span.hi),
              ident: Some(name),
 -            vis: pr,
 +            vis: vis,
              id: ast::DUMMY_NODE_ID,
              ty: ty,
              attrs: attrs,
  
      /// Parse a structure field declaration
      pub fn parse_single_struct_field(&mut self,
 +                                     lo: BytePos,
                                       vis: Visibility,
                                       attrs: Vec<Attribute> )
                                       -> PResult<'a, StructField> {
 -        let a_var = self.parse_name_and_ty(vis, attrs)?;
 +        let a_var = self.parse_name_and_ty(lo, vis, attrs)?;
          match self.token {
              token::Comma => {
                  self.bump();
      /// Parse an element of a struct definition
      fn parse_struct_decl_field(&mut self) -> PResult<'a, StructField> {
          let attrs = self.parse_outer_attributes()?;
 +        let lo = self.span.lo;
          let vis = self.parse_visibility(true)?;
 -        self.parse_single_struct_field(vis, attrs)
 +        self.parse_single_struct_field(lo, vis, attrs)
      }
  
      // If `allow_path` is false, just parse the `pub` in `pub(path)` (but still parse `pub(crate)`)