diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index b538c6a6eca7b..577c905a1d5a6 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -919,6 +919,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "when debug-printing compiler state, do not include spans"), // o/w tests have closure@path
     identify_regions: bool = (false, parse_bool, [UNTRACKED],
         "make unnamed regions display as '# (where # is some non-ident unique id)"),
+    emit_end_regions: bool = (false, parse_bool, [UNTRACKED],
+        "emit EndRegion as part of MIR; enable transforms that solely process EndRegion"),
     borrowck_mir: bool = (false, parse_bool, [UNTRACKED],
         "implicitly treat functions as if they have `#[rustc_mir_borrowck]` attribute"),
     time_passes: bool = (false, parse_bool, [UNTRACKED],
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 823a637c7e0d4..129a9f5575008 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -410,6 +410,10 @@ impl Session {
     pub fn print_llvm_passes(&self) -> bool {
         self.opts.debugging_opts.print_llvm_passes
     }
+    pub fn emit_end_regions(&self) -> bool {
+        self.opts.debugging_opts.emit_end_regions ||
+            (self.opts.debugging_opts.mir_emit_validate > 0)
+    }
     pub fn lto(&self) -> bool {
         self.opts.cg.lto
     }
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
index d77fe5170e040..a6e31bcddd242 100644
--- a/src/librustc_mir/build/cfg.rs
+++ b/src/librustc_mir/build/cfg.rs
@@ -16,6 +16,7 @@
 use build::CFG;
 use rustc::middle::region;
 use rustc::mir::*;
+use rustc::ty;
 
 impl<'tcx> CFG<'tcx> {
     pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
@@ -44,14 +45,17 @@ impl<'tcx> CFG<'tcx> {
         self.block_data_mut(block).statements.push(statement);
     }
 
-    pub fn push_end_region(&mut self,
-                           block: BasicBlock,
-                           source_info: SourceInfo,
-                           region_scope: region::Scope) {
-        self.push(block, Statement {
-            source_info,
-            kind: StatementKind::EndRegion(region_scope),
-        });
+    pub fn push_end_region<'a, 'gcx:'a+'tcx>(&mut self,
+                                             tcx: ty::TyCtxt<'a, 'gcx, 'tcx>,
+                                             block: BasicBlock,
+                                             source_info: SourceInfo,
+                                             region_scope: region::Scope) {
+        if tcx.sess.emit_end_regions() {
+            self.push(block, Statement {
+                source_info,
+                kind: StatementKind::EndRegion(region_scope),
+            });
+        }
     }
 
     pub fn push_assign(&mut self,
diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs
index ed598c876f3e9..c08620c1e4104 100644
--- a/src/librustc_mir/build/scope.rs
+++ b/src/librustc_mir/build/scope.rs
@@ -89,7 +89,7 @@ should go to.
 
 use build::{BlockAnd, BlockAndExtension, Builder, CFG};
 use rustc::middle::region;
-use rustc::ty::Ty;
+use rustc::ty::{Ty, TyCtxt};
 use rustc::mir::*;
 use rustc::mir::transform::MirSource;
 use syntax_pos::{Span};
@@ -359,7 +359,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                           self.arg_count,
                                           false));
 
-        self.cfg.push_end_region(block, region_scope.1, scope.region_scope);
+        self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
         block.unit()
     }
 
@@ -414,7 +414,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                               false));
 
             // End all regions for scopes out of which we are breaking.
-            self.cfg.push_end_region(block, region_scope.1, scope.region_scope);
+            self.cfg.push_end_region(self.hir.tcx(), block, region_scope.1, scope.region_scope);
         }
         }
         let scope = &self.scopes[len - scope_count];
@@ -463,7 +463,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                                               true));
 
             // End all regions for scopes out of which we are breaking.
-            self.cfg.push_end_region(block, src_info, scope.region_scope);
+            self.cfg.push_end_region(self.hir.tcx(), block, src_info, scope.region_scope);
         }
 
         self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop);
@@ -694,7 +694,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         };
 
         for scope in scopes.iter_mut() {
-            target = build_diverge_scope(cfg, scope.region_scope_span,
+            target = build_diverge_scope(self.hir.tcx(), cfg, scope.region_scope_span,
                                          scope, target, generator_drop);
         }
         Some(target)
@@ -831,7 +831,8 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
     block.unit()
 }
 
-fn build_diverge_scope<'a, 'gcx, 'tcx>(cfg: &mut CFG<'tcx>,
+fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                       cfg: &mut CFG<'tcx>,
                                        span: Span,
                                        scope: &mut Scope<'tcx>,
                                        mut target: BasicBlock,
@@ -893,7 +894,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(cfg: &mut CFG<'tcx>,
     // becomes trivial goto after pass that removes all EndRegions.)
     {
         let block = cfg.start_new_cleanup_block();
-        cfg.push_end_region(block, source_info(span), scope.region_scope);
+        cfg.push_end_region(tcx, block, source_info(span), scope.region_scope);
         cfg.terminate(block, source_info(span), TerminatorKind::Goto { target: target });
         target = block
     }
diff --git a/src/librustc_mir/transform/clean_end_regions.rs b/src/librustc_mir/transform/clean_end_regions.rs
index 55a16b2f39161..a6750f400ba93 100644
--- a/src/librustc_mir/transform/clean_end_regions.rs
+++ b/src/librustc_mir/transform/clean_end_regions.rs
@@ -39,9 +39,11 @@ struct DeleteTrivialEndRegions<'a> {
 
 impl MirPass for CleanEndRegions {
     fn run_pass<'a, 'tcx>(&self,
-                          _tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           _source: MirSource,
                           mir: &mut Mir<'tcx>) {
+        if !tcx.sess.emit_end_regions() { return; }
+
         let mut gather = GatherBorrowedRegions {
             seen_regions: FxHashSet()
         };
diff --git a/src/test/mir-opt/end_region_1.rs b/src/test/mir-opt/end_region_1.rs
index 54409d3543ebc..9c8cfc0ab208c 100644
--- a/src/test/mir-opt/end_region_1.rs
+++ b/src/test/mir-opt/end_region_1.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z identify_regions
+// compile-flags: -Z identify_regions -Z emit-end-regions
 // ignore-tidy-linelength
 
 // This is just about the simplest program that exhibits an EndRegion.
diff --git a/src/test/mir-opt/end_region_2.rs b/src/test/mir-opt/end_region_2.rs
index b37bd4188d970..6a4e209a14b7f 100644
--- a/src/test/mir-opt/end_region_2.rs
+++ b/src/test/mir-opt/end_region_2.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z identify_regions
+// compile-flags: -Z identify_regions -Z emit-end-regions
 // ignore-tidy-linelength
 
 // We will EndRegion for borrows in a loop that occur before break but
diff --git a/src/test/mir-opt/end_region_3.rs b/src/test/mir-opt/end_region_3.rs
index be9fc579ab636..cb1d45e37c834 100644
--- a/src/test/mir-opt/end_region_3.rs
+++ b/src/test/mir-opt/end_region_3.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z identify_regions
+// compile-flags: -Z identify_regions -Z emit-end-regions
 // ignore-tidy-linelength
 
 // Binding the borrow's subject outside the loop does not increase the
diff --git a/src/test/mir-opt/end_region_4.rs b/src/test/mir-opt/end_region_4.rs
index 58ce1ed5b84b7..b714b6bc55b24 100644
--- a/src/test/mir-opt/end_region_4.rs
+++ b/src/test/mir-opt/end_region_4.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z identify_regions
+// compile-flags: -Z identify_regions -Z emit-end-regions
 // ignore-tidy-linelength
 
 // Unwinding should EndRegion for in-scope borrows: Direct borrows.
diff --git a/src/test/mir-opt/end_region_5.rs b/src/test/mir-opt/end_region_5.rs
index be62a5473a6ff..a4c53675b9c3a 100644
--- a/src/test/mir-opt/end_region_5.rs
+++ b/src/test/mir-opt/end_region_5.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z identify_regions -Z span_free_formats
+// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions
 // ignore-tidy-linelength
 
 // Unwinding should EndRegion for in-scope borrows: Borrowing via by-ref closure.
diff --git a/src/test/mir-opt/end_region_6.rs b/src/test/mir-opt/end_region_6.rs
index 23b92583a11da..daa94769430df 100644
--- a/src/test/mir-opt/end_region_6.rs
+++ b/src/test/mir-opt/end_region_6.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z identify_regions -Z span_free_formats
+// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions
 // ignore-tidy-linelength
 
 // Unwinding should EndRegion for in-scope borrows: 2nd borrow within by-ref closure.
diff --git a/src/test/mir-opt/end_region_7.rs b/src/test/mir-opt/end_region_7.rs
index ee0615f2bb312..9feacd04fe0fa 100644
--- a/src/test/mir-opt/end_region_7.rs
+++ b/src/test/mir-opt/end_region_7.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z identify_regions -Z span_free_formats
+// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions
 // ignore-tidy-linelength
 
 // Unwinding should EndRegion for in-scope borrows: Borrow of moved data.
diff --git a/src/test/mir-opt/end_region_8.rs b/src/test/mir-opt/end_region_8.rs
index ef184e39c0061..30dda7a406260 100644
--- a/src/test/mir-opt/end_region_8.rs
+++ b/src/test/mir-opt/end_region_8.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z identify_regions -Z span_free_formats
+// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions
 // ignore-tidy-linelength
 
 // Unwinding should EndRegion for in-scope borrows: Move of borrow into closure.
diff --git a/src/test/mir-opt/end_region_9.rs b/src/test/mir-opt/end_region_9.rs
index 719bc3ff9dd04..bbfdc0e77a8d6 100644
--- a/src/test/mir-opt/end_region_9.rs
+++ b/src/test/mir-opt/end_region_9.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z identify_regions -Z span_free_formats
+// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions
 // ignore-tidy-linelength
 
 // This test models a scenario that arielb1 found during review.
diff --git a/src/test/mir-opt/issue-43457.rs b/src/test/mir-opt/issue-43457.rs
index 2a36672a45774..3f0f5068577c6 100644
--- a/src/test/mir-opt/issue-43457.rs
+++ b/src/test/mir-opt/issue-43457.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -Z identify_regions -Z span_free_formats
+// compile-flags: -Z identify_regions -Z span_free_formats -Z emit-end-regions
 // ignore-tidy-linelength
 
 // Regression test for #43457: an `EndRegion` was missing from output