From 97d47a5e7c41274eacbec55a4c08112407c78ff5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Sat, 8 Feb 2020 20:02:54 -0800
Subject: [PATCH 01/34] Account for type params on method without parens

---
 src/librustc_typeck/check/expr.rs              |  4 ++--
 src/librustc_typeck/check/method/mod.rs        | 18 +++++++++++++-----
 .../suggestions/method-missing-parentheses.rs  |  5 +++++
 .../method-missing-parentheses.stderr          | 17 +++++++++++++++++
 4 files changed, 37 insertions(+), 7 deletions(-)
 create mode 100644 src/test/ui/suggestions/method-missing-parentheses.rs
 create mode 100644 src/test/ui/suggestions/method-missing-parentheses.stderr

diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index 9ce89bd636304..90b7b300da9d5 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -1586,7 +1586,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 &format!("a method `{}` also exists, call it with parentheses", field),
                 field,
                 expr_t,
-                expr.hir_id,
+                expr,
             );
         }
         err.emit();
@@ -1609,7 +1609,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 "use parentheses to call the method",
                 field,
                 expr_t,
-                expr.hir_id,
+                expr,
             );
         } else {
             err.help("methods are immutable and cannot be assigned to");
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index e90c2ef5e4361..a75154b160a5c 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -135,7 +135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         msg: &str,
         method_name: ast::Ident,
         self_ty: Ty<'tcx>,
-        call_expr_id: hir::HirId,
+        call_expr: &hir::Expr<'_>,
     ) {
         let has_params = self
             .probe_for_name(
@@ -144,7 +144,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 method_name,
                 IsSuggestion(false),
                 self_ty,
-                call_expr_id,
+                call_expr.hir_id,
                 ProbeScope::TraitsInScope,
             )
             .and_then(|pick| {
@@ -152,13 +152,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Ok(sig.inputs().skip_binder().len() > 1)
             });
 
+        // Account for `foo.bar<T>`;
+        let sugg_span = method_name.span.with_hi(call_expr.span.hi());
+        let snippet = self
+            .tcx
+            .sess
+            .source_map()
+            .span_to_snippet(sugg_span)
+            .unwrap_or_else(|_| method_name.to_string());
         let (suggestion, applicability) = if has_params.unwrap_or_default() {
-            (format!("{}(...)", method_name), Applicability::HasPlaceholders)
+            (format!("{}(...)", snippet), Applicability::HasPlaceholders)
         } else {
-            (format!("{}()", method_name), Applicability::MaybeIncorrect)
+            (format!("{}()", snippet), Applicability::MaybeIncorrect)
         };
 
-        err.span_suggestion(method_name.span, msg, suggestion, applicability);
+        err.span_suggestion(sugg_span, msg, suggestion, applicability);
     }
 
     /// Performs method lookup. If lookup is successful, it will return the callee
diff --git a/src/test/ui/suggestions/method-missing-parentheses.rs b/src/test/ui/suggestions/method-missing-parentheses.rs
new file mode 100644
index 0000000000000..e1a85271ad0a3
--- /dev/null
+++ b/src/test/ui/suggestions/method-missing-parentheses.rs
@@ -0,0 +1,5 @@
+fn main() {
+    let _ = vec![].into_iter().collect::<usize>;
+    //~^ ERROR attempted to take value of method `collect` on type `std::vec::IntoIter<_>`
+    //~| ERROR field expressions may not have generic arguments
+}
diff --git a/src/test/ui/suggestions/method-missing-parentheses.stderr b/src/test/ui/suggestions/method-missing-parentheses.stderr
new file mode 100644
index 0000000000000..8569eb6f4ad1e
--- /dev/null
+++ b/src/test/ui/suggestions/method-missing-parentheses.stderr
@@ -0,0 +1,17 @@
+error: field expressions may not have generic arguments
+  --> $DIR/method-missing-parentheses.rs:2:41
+   |
+LL |     let _ = vec![].into_iter().collect::<usize>;
+   |                                         ^^^^^^^
+
+error[E0615]: attempted to take value of method `collect` on type `std::vec::IntoIter<_>`
+  --> $DIR/method-missing-parentheses.rs:2:32
+   |
+LL |     let _ = vec![].into_iter().collect::<usize>;
+   |                                ^^^^^^^---------
+   |                                |
+   |                                help: use parentheses to call the method: `collect::<usize>()`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0615`.

From 202d401c2504f17133c50505b82fe4278ab2c842 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 9 Feb 2020 15:23:34 +0100
Subject: [PATCH 02/34] miri: simplify singed operator overflow detection

---
 src/librustc_mir/interpret/operator.rs | 38 ++++++++++----------------
 1 file changed, 14 insertions(+), 24 deletions(-)

diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index 5050fe4906474..b4f6b5f89996b 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -134,9 +134,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             let mut r = r as u32;
             let size = left_layout.size;
             oflo |= r >= size.bits() as u32;
-            if oflo {
-                r %= size.bits() as u32;
-            }
+            r %= size.bits() as u32;
             let result = if signed {
                 let l = self.sign_extend(l, left_layout) as i128;
                 let result = match bin_op {
@@ -168,6 +166,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             )
         }
 
+        let size = left_layout.size;
+
         // Operations that need special treatment for signed integers
         if left_layout.abi.is_signed() {
             let op: Option<fn(&i128, &i128) -> bool> = match bin_op {
@@ -195,32 +195,20 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             if let Some(op) = op {
                 let l128 = self.sign_extend(l, left_layout) as i128;
                 let r = self.sign_extend(r, right_layout) as i128;
-                let size = left_layout.size;
-                match bin_op {
-                    Rem | Div => {
-                        // int_min / -1
-                        if r == -1 && l == (1 << (size.bits() - 1)) {
-                            return Ok((Scalar::from_uint(l, size), true, left_layout.ty));
-                        }
-                    }
-                    _ => {}
-                }
-                trace!("{}, {}, {}", l, l128, r);
-                let (result, mut oflo) = op(l128, r);
-                trace!("{}, {}", result, oflo);
-                if !oflo && size.bits() != 128 {
-                    let max = 1 << (size.bits() - 1);
-                    oflo = result >= max || result < -max;
-                }
-                // this may be out-of-bounds for the result type, so we have to truncate ourselves
+
+                let (result, oflo) = op(l128, r);
+                // This may be out-of-bounds for the result type, so we have to truncate ourselves.
+                // If that truncation loses any information, we have an overflow.
                 let result = result as u128;
                 let truncated = self.truncate(result, left_layout);
-                return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty));
+                return Ok((
+                    Scalar::from_uint(truncated, size),
+                    oflo || self.sign_extend(truncated, left_layout) != result,
+                    left_layout.ty,
+                ));
             }
         }
 
-        let size = left_layout.size;
-
         let (val, ty) = match bin_op {
             Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
             Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
@@ -247,6 +235,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     _ => bug!(),
                 };
                 let (result, oflo) = op(l, r);
+                // Truncate to target type.
+                // If that truncation loses any information, we have an overflow.
                 let truncated = self.truncate(result, left_layout);
                 return Ok((
                     Scalar::from_uint(truncated, size),

From 28f85c6ffad77554150e7cab4ccac38b26621bdb Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 9 Feb 2020 15:41:40 +0100
Subject: [PATCH 03/34] bring back extra check for int_min%-1

---
 src/librustc_mir/interpret/operator.rs | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index b4f6b5f89996b..abe437bd8d7c6 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -195,6 +195,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
             if let Some(op) = op {
                 let l128 = self.sign_extend(l, left_layout) as i128;
                 let r = self.sign_extend(r, right_layout) as i128;
+                // We need a special check for overflowing remainder:
+                // "int_min % -1" overflows and returns 0, but after casting things to a larger int
+                // type it does *not* overflow nor give an unrepresentable result!
+                match bin_op {
+                    Rem => {
+                        if r == -1 && l == (1 << (size.bits() - 1)) {
+                            return Ok((Scalar::from_int(0, size), true, left_layout.ty));
+                        }
+                    }
+                    _ => {}
+                }
 
                 let (result, oflo) = op(l128, r);
                 // This may be out-of-bounds for the result type, so we have to truncate ourselves.

From 7d2f6ae00149e4fdfeb9eedc9cb7433f6e67cf42 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sat, 8 Feb 2020 23:27:29 +0100
Subject: [PATCH 04/34] miri: equip unary_op with overflow detection

---
 src/librustc_mir/interpret/operator.rs | 36 +++++++++++++++++++-------
 1 file changed, 27 insertions(+), 9 deletions(-)

diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index abe437bd8d7c6..9a3c08248b5ef 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -342,7 +342,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
     }
 
-    /// Typed version of `checked_binary_op`, returning an `ImmTy`. Also ignores overflows.
+    /// Typed version of `overflowing_binary_op`, returning an `ImmTy`. Also ignores overflows.
     #[inline]
     pub fn binary_op(
         &self,
@@ -354,11 +354,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
     }
 
-    pub fn unary_op(
+    /// Returns the result of the specified operation, whether it overflowed, and
+    /// the result type.
+    pub fn overflowing_unary_op(
         &self,
         un_op: mir::UnOp,
         val: ImmTy<'tcx, M::PointerTag>,
-    ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, (Scalar<M::PointerTag>, bool, Ty<'tcx>)> {
         use rustc::mir::UnOp::*;
 
         let layout = val.layout;
@@ -372,7 +374,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     Not => !val,
                     _ => bug!("Invalid bool op {:?}", un_op),
                 };
-                Ok(ImmTy::from_scalar(Scalar::from_bool(res), self.layout_of(self.tcx.types.bool)?))
+                Ok((Scalar::from_bool(res), false, self.tcx.types.bool))
             }
             ty::Float(fty) => {
                 let res = match (un_op, fty) {
@@ -380,21 +382,37 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
                     _ => bug!("Invalid float op {:?}", un_op),
                 };
-                Ok(ImmTy::from_scalar(res, layout))
+                Ok((res, false, layout.ty))
             }
             _ => {
                 assert!(layout.ty.is_integral());
                 let val = self.force_bits(val, layout.size)?;
-                let res = match un_op {
-                    Not => !val,
+                let (res, overflow) = match un_op {
+                    Not => (self.truncate(!val, layout), false), // bitwise negation, then truncate
                     Neg => {
+                        // arithmetic negation
                         assert!(layout.abi.is_signed());
-                        (-(val as i128)) as u128
+                        let val = self.sign_extend(val, layout) as i128;
+                        let (res, overflow) = val.overflowing_neg();
+                        let res = res as u128;
+                        // Truncate to target type.
+                        // If that truncation loses any information, we have an overflow.
+                        let truncated = self.truncate(res, layout);
+                        (truncated, overflow || self.sign_extend(truncated, layout) != res)
                     }
                 };
                 // res needs tuncating
-                Ok(ImmTy::from_uint(self.truncate(res, layout), layout))
+                Ok((Scalar::from_uint(res, layout.size), overflow, layout.ty))
             }
         }
     }
+
+    pub fn unary_op(
+        &self,
+        un_op: mir::UnOp,
+        val: ImmTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
+        let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?;
+        Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
+    }
 }

From ae23f7020a5cb9a201e83f20f151282368b1f494 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 9 Feb 2020 15:48:18 +0100
Subject: [PATCH 05/34] const-prop: use overflowing_unary_op for overflowing
 checking of unary ops

---
 src/librustc_mir/transform/const_prop.rs | 34 ++++++++++++------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index d645f6cf183b4..d09165f904ab2 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -518,18 +518,19 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         }
     }
 
-    fn check_unary_op(&mut self, arg: &Operand<'tcx>, source_info: SourceInfo) -> Option<()> {
+    fn check_unary_op(
+        &mut self,
+        op: UnOp,
+        arg: &Operand<'tcx>,
+        source_info: SourceInfo,
+    ) -> Option<()> {
         self.use_ecx(source_info, |this| {
-            let ty = arg.ty(&this.local_decls, this.tcx);
-
-            if ty.is_integral() {
-                let arg = this.ecx.eval_operand(arg, None)?;
-                let prim = this.ecx.read_immediate(arg)?;
-                // Need to do overflow check here: For actual CTFE, MIR
-                // generation emits code that does this before calling the op.
-                if prim.to_bits()? == (1 << (prim.layout.size.bits() - 1)) {
-                    throw_panic!(OverflowNeg)
-                }
+            let val = this.ecx.read_immediate(this.ecx.eval_operand(arg, None)?)?;
+            let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, val)?;
+
+            if overflow {
+                assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
+                throw_panic!(OverflowNeg);
             }
 
             Ok(())
@@ -574,11 +575,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
         if !overflow_check {
             self.use_ecx(source_info, |this| {
                 let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?;
-                let (_, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
+                let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
 
                 if overflow {
-                    let err = err_panic!(Overflow(op)).into();
-                    return Err(err);
+                    throw_panic!(Overflow(op));
                 }
 
                 Ok(())
@@ -618,9 +618,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             // Additional checking: if overflow checks are disabled (which is usually the case in
             // release mode), then we need to do additional checking here to give lints to the user
             // if an overflow would occur.
-            Rvalue::UnaryOp(UnOp::Neg, arg) if !overflow_check => {
-                trace!("checking UnaryOp(op = Neg, arg = {:?})", arg);
-                self.check_unary_op(arg, source_info)?;
+            Rvalue::UnaryOp(op, arg) if !overflow_check => {
+                trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg);
+                self.check_unary_op(*op, arg, source_info)?;
             }
 
             // Additional checking: check for overflows on integer binary operations and report

From b434d7ef8ae19c145dd9348b70bb955147dfab70 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Mon, 10 Feb 2020 09:56:17 +0100
Subject: [PATCH 06/34] add test that checks overflows on arithmetic operators

---
 .../consts/const-int-arithmetic-overflow.rs   | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 src/test/ui/consts/const-int-arithmetic-overflow.rs

diff --git a/src/test/ui/consts/const-int-arithmetic-overflow.rs b/src/test/ui/consts/const-int-arithmetic-overflow.rs
new file mode 100644
index 0000000000000..75dac812f1e3a
--- /dev/null
+++ b/src/test/ui/consts/const-int-arithmetic-overflow.rs
@@ -0,0 +1,26 @@
+// run-pass
+// compile-flags: -O
+#![allow(const_err)]
+
+// Make sure arithmetic unary/binary ops actually return the right result, even when overflowing.
+// We have to put them in `const fn` and turn on optimizations to avoid overflow checks.
+
+const fn add(x: i8, y: i8) -> i8 { x+y }
+const fn sub(x: i8, y: i8) -> i8 { x-y }
+const fn mul(x: i8, y: i8) -> i8 { x*y }
+// div and rem are always checked, so we cannot test their result in case of oveflow.
+const fn neg(x: i8) -> i8 { -x }
+
+fn main() {
+    const ADD_OFLOW: i8 = add(100, 100);
+    assert_eq!(ADD_OFLOW, -56);
+
+    const SUB_OFLOW: i8 = sub(100, -100);
+    assert_eq!(SUB_OFLOW, -56);
+
+    const MUL_OFLOW: i8 = mul(-100, -2);
+    assert_eq!(MUL_OFLOW, -56);
+
+    const NEG_OFLOW: i8 = neg(-128);
+    assert_eq!(NEG_OFLOW, -128);
+}

From 1ddb0503ff1e203de40f5bbc1e0b00d1b4e99d12 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Mon, 10 Feb 2020 11:23:04 +0100
Subject: [PATCH 07/34] div/rem overflow tests: also test i128

---
 src/test/ui/issues/issue-8460-const.rs      | 12 +++-
 src/test/ui/issues/issue-8460-const.stderr  | 78 +++++++++++++++------
 src/test/ui/issues/issue-8460-const2.rs     | 10 ++-
 src/test/ui/issues/issue-8460-const2.stderr | 56 ++++++++++-----
 4 files changed, 117 insertions(+), 39 deletions(-)

diff --git a/src/test/ui/issues/issue-8460-const.rs b/src/test/ui/issues/issue-8460-const.rs
index c18a0d4d6cbbe..5866cef2d2c70 100644
--- a/src/test/ui/issues/issue-8460-const.rs
+++ b/src/test/ui/issues/issue-8460-const.rs
@@ -3,7 +3,7 @@
 
 #![deny(const_err)]
 
-use std::{isize, i8, i16, i32, i64};
+use std::{isize, i8, i16, i32, i64, i128};
 use std::thread;
 
 fn main() {
@@ -22,6 +22,9 @@ fn main() {
     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
     //~^ ERROR attempt to divide with overflow
     //~| ERROR this expression will panic at runtime
+    assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
+    //~^ ERROR attempt to divide with overflow
+    //~| ERROR this expression will panic at runtime
     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
@@ -32,6 +35,8 @@ fn main() {
     //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
+    assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
+    //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
     //~| ERROR this expression will panic at runtime
@@ -47,6 +52,9 @@ fn main() {
     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
     //~| ERROR this expression will panic at runtime
+    assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
+    //~^ ERROR attempt to calculate the remainder with overflow
+    //~| ERROR this expression will panic at runtime
     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
@@ -57,4 +65,6 @@ fn main() {
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
+    assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
+    //~^ ERROR attempt to calculate the remainder with a divisor of zero
 }
diff --git a/src/test/ui/issues/issue-8460-const.stderr b/src/test/ui/issues/issue-8460-const.stderr
index 6b1d74094a10b..d7373948cb9e0 100644
--- a/src/test/ui/issues/issue-8460-const.stderr
+++ b/src/test/ui/issues/issue-8460-const.stderr
@@ -64,125 +64,161 @@ error: this expression will panic at runtime
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to divide with overflow
 
-error: attempt to divide by zero
+error: attempt to divide with overflow
+  --> $DIR/issue-8460-const.rs:25:36
+   |
+LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^
+
+error: this expression will panic at runtime
   --> $DIR/issue-8460-const.rs:25:36
    |
+LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^ attempt to divide with overflow
+
+error: attempt to divide by zero
+  --> $DIR/issue-8460-const.rs:28:36
+   |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
    |                                    ^^^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const.rs:27:36
+  --> $DIR/issue-8460-const.rs:30:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
    |                                    ^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const.rs:29:36
+  --> $DIR/issue-8460-const.rs:32:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const.rs:31:36
+  --> $DIR/issue-8460-const.rs:34:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const.rs:33:36
+  --> $DIR/issue-8460-const.rs:36:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
+error: attempt to divide by zero
+  --> $DIR/issue-8460-const.rs:38:36
+   |
+LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
+   |                                    ^^^^^^^^^
+
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const.rs:35:36
+  --> $DIR/issue-8460-const.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/issue-8460-const.rs:35:36
+  --> $DIR/issue-8460-const.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const.rs:38:36
+  --> $DIR/issue-8460-const.rs:43:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/issue-8460-const.rs:38:36
+  --> $DIR/issue-8460-const.rs:43:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^ attempt to calculate the remainder with overflow
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const.rs:41:36
+  --> $DIR/issue-8460-const.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/issue-8460-const.rs:41:36
+  --> $DIR/issue-8460-const.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const.rs:44:36
+  --> $DIR/issue-8460-const.rs:49:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/issue-8460-const.rs:44:36
+  --> $DIR/issue-8460-const.rs:49:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const.rs:47:36
+  --> $DIR/issue-8460-const.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/issue-8460-const.rs:47:36
+  --> $DIR/issue-8460-const.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
 
+error: attempt to calculate the remainder with overflow
+  --> $DIR/issue-8460-const.rs:55:36
+   |
+LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^
+
+error: this expression will panic at runtime
+  --> $DIR/issue-8460-const.rs:55:36
+   |
+LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^ attempt to calculate the remainder with overflow
+
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const.rs:50:36
+  --> $DIR/issue-8460-const.rs:58:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
    |                                    ^^^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const.rs:52:36
+  --> $DIR/issue-8460-const.rs:60:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
    |                                    ^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const.rs:54:36
+  --> $DIR/issue-8460-const.rs:62:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const.rs:56:36
+  --> $DIR/issue-8460-const.rs:64:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const.rs:58:36
+  --> $DIR/issue-8460-const.rs:66:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
-error: aborting due to 30 previous errors
+error: attempt to calculate the remainder with a divisor of zero
+  --> $DIR/issue-8460-const.rs:68:36
+   |
+LL |     assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
+   |                                    ^^^^^^^^^
+
+error: aborting due to 36 previous errors
 
diff --git a/src/test/ui/issues/issue-8460-const2.rs b/src/test/ui/issues/issue-8460-const2.rs
index 0ca850abc1b60..afea859bb65a9 100644
--- a/src/test/ui/issues/issue-8460-const2.rs
+++ b/src/test/ui/issues/issue-8460-const2.rs
@@ -3,7 +3,7 @@
 
 #![deny(const_err)]
 
-use std::{isize, i8, i16, i32, i64};
+use std::{isize, i8, i16, i32, i64, i128};
 use std::thread;
 
 fn main() {
@@ -17,6 +17,8 @@ fn main() {
     //~^ ERROR attempt to divide with overflow
     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
     //~^ ERROR attempt to divide with overflow
+    assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
+    //~^ ERROR attempt to divide with overflow
     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
@@ -27,6 +29,8 @@ fn main() {
     //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
     //~^ ERROR attempt to divide by zero
+    assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
+    //~^ ERROR attempt to divide by zero
     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
@@ -37,6 +41,8 @@ fn main() {
     //~^ ERROR attempt to calculate the remainder with overflow
     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with overflow
+    assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
+    //~^ ERROR attempt to calculate the remainder with overflow
     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
@@ -47,4 +53,6 @@ fn main() {
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
     //~^ ERROR attempt to calculate the remainder with a divisor of zero
+    assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
+    //~^ ERROR attempt to calculate the remainder with a divisor of zero
 }
diff --git a/src/test/ui/issues/issue-8460-const2.stderr b/src/test/ui/issues/issue-8460-const2.stderr
index 63b9123e95097..e25d560fe0ce3 100644
--- a/src/test/ui/issues/issue-8460-const2.stderr
+++ b/src/test/ui/issues/issue-8460-const2.stderr
@@ -34,95 +34,119 @@ error: attempt to divide with overflow
 LL |     assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
-error: attempt to divide by zero
+error: attempt to divide with overflow
   --> $DIR/issue-8460-const2.rs:20:36
    |
+LL |     assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^
+
+error: attempt to divide by zero
+  --> $DIR/issue-8460-const2.rs:22:36
+   |
 LL |     assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
    |                                    ^^^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const2.rs:22:36
+  --> $DIR/issue-8460-const2.rs:24:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
    |                                    ^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const2.rs:24:36
+  --> $DIR/issue-8460-const2.rs:26:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const2.rs:26:36
+  --> $DIR/issue-8460-const2.rs:28:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to divide by zero
-  --> $DIR/issue-8460-const2.rs:28:36
+  --> $DIR/issue-8460-const2.rs:30:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
    |                                    ^^^^^^^^
 
+error: attempt to divide by zero
+  --> $DIR/issue-8460-const2.rs:32:36
+   |
+LL |     assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err());
+   |                                    ^^^^^^^^^
+
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const2.rs:30:36
+  --> $DIR/issue-8460-const2.rs:34:36
    |
 LL |     assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^^^
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const2.rs:32:36
+  --> $DIR/issue-8460-const2.rs:36:36
    |
 LL |     assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const2.rs:34:36
+  --> $DIR/issue-8460-const2.rs:38:36
    |
 LL |     assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const2.rs:36:36
+  --> $DIR/issue-8460-const2.rs:40:36
    |
 LL |     assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
 error: attempt to calculate the remainder with overflow
-  --> $DIR/issue-8460-const2.rs:38:36
+  --> $DIR/issue-8460-const2.rs:42:36
    |
 LL |     assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
    |                                    ^^^^^^^^^^^^^
 
+error: attempt to calculate the remainder with overflow
+  --> $DIR/issue-8460-const2.rs:44:36
+   |
+LL |     assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err());
+   |                                    ^^^^^^^^^^^^^^
+
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const2.rs:40:36
+  --> $DIR/issue-8460-const2.rs:46:36
    |
 LL |     assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
    |                                    ^^^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const2.rs:42:36
+  --> $DIR/issue-8460-const2.rs:48:36
    |
 LL |     assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
    |                                    ^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const2.rs:44:36
+  --> $DIR/issue-8460-const2.rs:50:36
    |
 LL |     assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const2.rs:46:36
+  --> $DIR/issue-8460-const2.rs:52:36
    |
 LL |     assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
 error: attempt to calculate the remainder with a divisor of zero
-  --> $DIR/issue-8460-const2.rs:48:36
+  --> $DIR/issue-8460-const2.rs:54:36
    |
 LL |     assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
    |                                    ^^^^^^^^
 
-error: aborting due to 20 previous errors
+error: attempt to calculate the remainder with a divisor of zero
+  --> $DIR/issue-8460-const2.rs:56:36
+   |
+LL |     assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err());
+   |                                    ^^^^^^^^^
+
+error: aborting due to 24 previous errors
 

From d6c5a04eff9643b634cb2c98411f973b8f7aa1e2 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Mon, 10 Feb 2020 11:37:02 +0100
Subject: [PATCH 08/34] some more tests for i128 oveflow behavior

---
 src/test/ui/consts/const-err2.rs           |  8 +++++++-
 src/test/ui/consts/const-err2.stderr       | 22 +++++++++++++++++-----
 src/test/ui/consts/const-err3.rs           |  6 ++++++
 src/test/ui/consts/const-err3.stderr       | 22 +++++++++++++++++-----
 src/test/ui/consts/const-int-arithmetic.rs | 21 +++++++++++++++++++--
 5 files changed, 66 insertions(+), 13 deletions(-)

diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs
index 351dfd2e0f58c..7c5aaedda35fa 100644
--- a/src/test/ui/consts/const-err2.rs
+++ b/src/test/ui/consts/const-err2.rs
@@ -17,16 +17,22 @@ fn black_box<T>(_: T) {
 fn main() {
     let a = -std::i8::MIN;
     //~^ ERROR const_err
+    let a_i128 = -std::i128::MIN;
+    //~^ ERROR const_err
     let b = 200u8 + 200u8 + 200u8;
     //~^ ERROR const_err
+    let b_i128 = std::i128::MIN - std::i128::MAX;
+    //~^ ERROR const_err
     let c = 200u8 * 4;
     //~^ ERROR const_err
     let d = 42u8 - (42u8 + 1);
     //~^ ERROR const_err
     let _e = [5u8][1];
-    //~^ ERROR index out of bounds
+    //~^ ERROR const_err
     black_box(a);
+    black_box(a_i128);
     black_box(b);
+    black_box(b_i128);
     black_box(c);
     black_box(d);
 }
diff --git a/src/test/ui/consts/const-err2.stderr b/src/test/ui/consts/const-err2.stderr
index a76b6d1775f04..f135bf0b06cad 100644
--- a/src/test/ui/consts/const-err2.stderr
+++ b/src/test/ui/consts/const-err2.stderr
@@ -11,28 +11,40 @@ LL | #![deny(const_err)]
    |         ^^^^^^^^^
 
 error: this expression will panic at runtime
-  --> $DIR/const-err2.rs:20:13
+  --> $DIR/const-err2.rs:20:18
+   |
+LL |     let a_i128 = -std::i128::MIN;
+   |                  ^^^^^^^^^^^^^^^ attempt to negate with overflow
+
+error: this expression will panic at runtime
+  --> $DIR/const-err2.rs:22:13
    |
 LL |     let b = 200u8 + 200u8 + 200u8;
    |             ^^^^^^^^^^^^^ attempt to add with overflow
 
 error: this expression will panic at runtime
-  --> $DIR/const-err2.rs:22:13
+  --> $DIR/const-err2.rs:24:18
+   |
+LL |     let b_i128 = std::i128::MIN - std::i128::MAX;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+
+error: this expression will panic at runtime
+  --> $DIR/const-err2.rs:26:13
    |
 LL |     let c = 200u8 * 4;
    |             ^^^^^^^^^ attempt to multiply with overflow
 
 error: this expression will panic at runtime
-  --> $DIR/const-err2.rs:24:13
+  --> $DIR/const-err2.rs:28:13
    |
 LL |     let d = 42u8 - (42u8 + 1);
    |             ^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
 
 error: index out of bounds: the len is 1 but the index is 1
-  --> $DIR/const-err2.rs:26:14
+  --> $DIR/const-err2.rs:30:14
    |
 LL |     let _e = [5u8][1];
    |              ^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/consts/const-err3.rs b/src/test/ui/consts/const-err3.rs
index ab3823efd301d..43aba4a8b012b 100644
--- a/src/test/ui/consts/const-err3.rs
+++ b/src/test/ui/consts/const-err3.rs
@@ -17,8 +17,12 @@ fn black_box<T>(_: T) {
 fn main() {
     let a = -std::i8::MIN;
     //~^ ERROR const_err
+    let a_i128 = -std::i128::MIN;
+    //~^ ERROR const_err
     let b = 200u8 + 200u8 + 200u8;
     //~^ ERROR const_err
+    let b_i128 = std::i128::MIN - std::i128::MAX;
+    //~^ ERROR const_err
     let c = 200u8 * 4;
     //~^ ERROR const_err
     let d = 42u8 - (42u8 + 1);
@@ -26,7 +30,9 @@ fn main() {
     let _e = [5u8][1];
     //~^ ERROR const_err
     black_box(a);
+    black_box(a_i128);
     black_box(b);
+    black_box(b_i128);
     black_box(c);
     black_box(d);
 }
diff --git a/src/test/ui/consts/const-err3.stderr b/src/test/ui/consts/const-err3.stderr
index 02b912e928c80..05f64b87fcce6 100644
--- a/src/test/ui/consts/const-err3.stderr
+++ b/src/test/ui/consts/const-err3.stderr
@@ -10,29 +10,41 @@ note: the lint level is defined here
 LL | #![deny(const_err)]
    |         ^^^^^^^^^
 
+error: attempt to negate with overflow
+  --> $DIR/const-err3.rs:20:18
+   |
+LL |     let a_i128 = -std::i128::MIN;
+   |                  ^^^^^^^^^^^^^^^
+
 error: attempt to add with overflow
-  --> $DIR/const-err3.rs:20:13
+  --> $DIR/const-err3.rs:22:13
    |
 LL |     let b = 200u8 + 200u8 + 200u8;
    |             ^^^^^^^^^^^^^
 
+error: attempt to subtract with overflow
+  --> $DIR/const-err3.rs:24:18
+   |
+LL |     let b_i128 = std::i128::MIN - std::i128::MAX;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: attempt to multiply with overflow
-  --> $DIR/const-err3.rs:22:13
+  --> $DIR/const-err3.rs:26:13
    |
 LL |     let c = 200u8 * 4;
    |             ^^^^^^^^^
 
 error: attempt to subtract with overflow
-  --> $DIR/const-err3.rs:24:13
+  --> $DIR/const-err3.rs:28:13
    |
 LL |     let d = 42u8 - (42u8 + 1);
    |             ^^^^^^^^^^^^^^^^^
 
 error: index out of bounds: the len is 1 but the index is 1
-  --> $DIR/const-err3.rs:26:14
+  --> $DIR/const-err3.rs:30:14
    |
 LL |     let _e = [5u8][1];
    |              ^^^^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/consts/const-int-arithmetic.rs b/src/test/ui/consts/const-int-arithmetic.rs
index cfa2873c68bad..2c3421b7a8d0b 100644
--- a/src/test/ui/consts/const-int-arithmetic.rs
+++ b/src/test/ui/consts/const-int-arithmetic.rs
@@ -7,7 +7,7 @@
 #![feature(const_saturating_int_methods)]
 #![feature(const_wrapping_int_methods)]
 
-use std::i8;
+use std::{i8, i128};
 
 macro_rules! suite {
     ($(
@@ -65,6 +65,10 @@ suite!(
         C26: 5i8.checked_rem_euclid(0), None;
         C27: i8::MIN.checked_rem_euclid(-1), None;
     }
+    checked_i128 -> Option<i128> {
+        CHK_ADD_I128: i128::MAX.checked_add(1), None;
+        CHK_MUL_I128: i128::MIN.checked_mul(-1), None;
+    }
 
     saturating_and_wrapping -> i8 {
         // `const_saturating_int_methods`
@@ -104,6 +108,13 @@ suite!(
         C47: 100i8.wrapping_rem_euclid(10), 0;
         C48: (-128i8).wrapping_rem_euclid(-1), 0;
     }
+    saturating_and_wrapping_i128 -> i128 {
+        SAT_ADD_I128: i128::MAX.saturating_add(1), i128::MAX;
+        SAT_MUL_I128: i128::MAX.saturating_mul(2), i128::MAX;
+
+        WRP_ADD_I128: i128::MAX.wrapping_add(1), i128::MIN;
+        WRP_MUL_I128: i128::MAX.wrapping_mul(3), i128::MAX-2;
+    }
 
     overflowing -> (i8, bool) {
         // `const_overflowing_int_methods`
@@ -119,12 +130,18 @@ suite!(
 
         C55: 5i8.overflowing_rem_euclid(2), (1, false);
         C56: i8::MIN.overflowing_rem_euclid(-1), (0, true);
-
+    }
+    overflowing_i128 -> (i128, bool) {
+        OFL_ADD_I128: i128::MAX.overflowing_add(1), (i128::MIN, true);
+        OFL_MUL_I128: i128::MAX.overflowing_mul(3), (i128::MAX-2, true);
     }
 );
 
 fn main() {
    checked();
+   checked_i128();
    saturating_and_wrapping();
+   saturating_and_wrapping_i128();
    overflowing();
+   overflowing_i128();
 }

From aeedc9dea9e0460488e0b6ce7fe3aaf50395774c Mon Sep 17 00:00:00 2001
From: Raoul Strackx <raoul.strackx@fortanix.com>
Date: Fri, 7 Feb 2020 10:37:53 +0100
Subject: [PATCH 09/34] Corrected ac_mitigation patch. That patch used the
 untrusted stack to clear rflags during enclave (re-)entry

---
 src/libstd/sys/sgx/abi/entry.S | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
index a3e059e813173..7c273a8a83d30 100644
--- a/src/libstd/sys/sgx/abi/entry.S
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -134,6 +134,17 @@ elf_entry:
     ud2                               /* should not be reached  */
 /*  end elf_entry */
 
+/* This code needs to be called *after* the enclave stack has been setup. */
+/* There are 3 places where this needs to happen, so this is put in a macro. */
+.macro sanitize_rflags
+/*  Sanitize rflags received from user */
+/*    - DF flag: x86-64 ABI requires DF to be unset at function entry/exit */
+/*    - AC flag: AEX on misaligned memory accesses leaks side channel info */
+    pushfq
+    andq $~0x40400, (%rsp)
+    popfq
+.endm
+
 .text
 .global sgx_entry
 .type sgx_entry,function
@@ -150,13 +161,6 @@ sgx_entry:
     stmxcsr %gs:tcsls_user_mxcsr
     fnstcw %gs:tcsls_user_fcw
 
-/*  reset user state */
-/*    - DF flag: x86-64 ABI requires DF to be unset at function entry/exit */
-/*    - AC flag: AEX on misaligned memory accesses leaks side channel info */
-    pushfq
-    andq $~0x40400, (%rsp)
-    popfq
-
 /*  check for debug buffer pointer */
     testb  $0xff,DEBUG(%rip)
     jz .Lskip_debug_init
@@ -179,6 +183,7 @@ sgx_entry:
     lea IMAGE_BASE(%rip),%rax
     add %rax,%rsp
     mov %rsp,%gs:tcsls_tos
+    sanitize_rflags
 /*  call tcs_init */
 /*  store caller-saved registers in callee-saved registers */
     mov %rdi,%rbx
@@ -194,7 +199,10 @@ sgx_entry:
     mov %r13,%rdx
     mov %r14,%r8
     mov %r15,%r9
+    jmp .Lafter_init
 .Lskip_init:
+    sanitize_rflags
+.Lafter_init:
 /*  call into main entry point */
     load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
     call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */
@@ -292,6 +300,7 @@ usercall:
     movq $0,%gs:tcsls_last_rsp
 /*  restore callee-saved state, cf. "save" above */
     mov %r11,%rsp
+    sanitize_rflags
     ldmxcsr (%rsp)
     fldcw 4(%rsp)
     add $8, %rsp

From 236ab6e6d631f073a8c3c7439af6b2ec58ce1f25 Mon Sep 17 00:00:00 2001
From: Raoul Strackx <raoul.strackx@fortanix.com>
Date: Fri, 7 Feb 2020 10:49:47 +0100
Subject: [PATCH 10/34] sanitize MXCSR/FPU control registers

---
 src/libstd/sys/sgx/abi/entry.S | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
index 7c273a8a83d30..a08caec3c2b35 100644
--- a/src/libstd/sys/sgx/abi/entry.S
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -30,6 +30,14 @@ IMAGE_BASE:
 
 /*  We can store a bunch of data in the gap between MXCSR and the XSAVE header */
 
+/* MXCSR initialization value for ABI */
+.Lmxcsr_init:
+    .int 0x1f80
+
+/* x87 FPU control word initialization value for ABI */
+.Lfpucw_init:
+    .int 0x037f
+
 /*  The following symbols point at read-only data that will be filled in by the */
 /*  post-linker. */
 
@@ -173,6 +181,9 @@ sgx_entry:
     mov %gs:tcsls_last_rsp,%r11
     test %r11,%r11
     jnz .Lusercall_ret
+/*  reset user state */
+    ldmxcsr .Lmxcsr_init(%rip)
+    fldcw .Lfpucw_init(%rip)
 /*  setup stack */
     mov %gs:tcsls_tos,%rsp /*  initially, RSP is not set to the correct value */
                            /*  here. This is fixed below under "adjust stack". */

From 71b9ed4a36748be01826063951310a2da2717a9b Mon Sep 17 00:00:00 2001
From: Jethro Beekman <jethro@fortanix.com>
Date: Mon, 10 Feb 2020 21:00:22 +0100
Subject: [PATCH 11/34] Avoid jumping to Rust code with user %rsp
 (reentry_panic)

---
 src/libstd/sys/sgx/abi/entry.S | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
index a08caec3c2b35..ed4db287229dc 100644
--- a/src/libstd/sys/sgx/abi/entry.S
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -144,13 +144,15 @@ elf_entry:
 
 /* This code needs to be called *after* the enclave stack has been setup. */
 /* There are 3 places where this needs to happen, so this is put in a macro. */
-.macro sanitize_rflags
+.macro entry_sanitize_final
 /*  Sanitize rflags received from user */
 /*    - DF flag: x86-64 ABI requires DF to be unset at function entry/exit */
 /*    - AC flag: AEX on misaligned memory accesses leaks side channel info */
     pushfq
     andq $~0x40400, (%rsp)
     popfq
+    bt $0,.Laborted(%rip)
+    jc .Lreentry_panic
 .endm
 
 .text
@@ -174,9 +176,6 @@ sgx_entry:
     jz .Lskip_debug_init
     mov %r10,%gs:tcsls_debug_panic_buf_ptr
 .Lskip_debug_init:
-/*  check for abort */
-    bt $0,.Laborted(%rip)
-    jc .Lreentry_panic
 /*  check if returning from usercall */
     mov %gs:tcsls_last_rsp,%r11
     test %r11,%r11
@@ -194,7 +193,7 @@ sgx_entry:
     lea IMAGE_BASE(%rip),%rax
     add %rax,%rsp
     mov %rsp,%gs:tcsls_tos
-    sanitize_rflags
+    entry_sanitize_final
 /*  call tcs_init */
 /*  store caller-saved registers in callee-saved registers */
     mov %rdi,%rbx
@@ -212,7 +211,7 @@ sgx_entry:
     mov %r15,%r9
     jmp .Lafter_init
 .Lskip_init:
-    sanitize_rflags
+    entry_sanitize_final
 .Lafter_init:
 /*  call into main entry point */
     load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
@@ -311,10 +310,10 @@ usercall:
     movq $0,%gs:tcsls_last_rsp
 /*  restore callee-saved state, cf. "save" above */
     mov %r11,%rsp
-    sanitize_rflags
     ldmxcsr (%rsp)
     fldcw 4(%rsp)
     add $8, %rsp
+    entry_sanitize_final
     pop %rbx
     pop %rbp
     pop %r12

From c561d23a6105122a517c14394a46c3faab8e01b6 Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Mon, 10 Feb 2020 22:58:31 +0100
Subject: [PATCH 12/34] remove outdated comment

---
 src/librustc_mir/interpret/operator.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index 9a3c08248b5ef..2e8c94903ca46 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -401,7 +401,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                         (truncated, overflow || self.sign_extend(truncated, layout) != res)
                     }
                 };
-                // res needs tuncating
                 Ok((Scalar::from_uint(res, layout.size), overflow, layout.ty))
             }
         }

From 9d91489526121ef3408e1efa2a98bcaefdedd9bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Esteban=20K=C3=BCber?= <esteban@kuber.com.ar>
Date: Mon, 10 Feb 2020 13:58:36 -0800
Subject: [PATCH 13/34] review comment: wording

---
 src/librustc_parse/parser/expr.rs                         | 2 +-
 src/test/ui/parser/type-parameters-in-field-exprs.rs      | 6 +++---
 src/test/ui/parser/type-parameters-in-field-exprs.stderr  | 6 +++---
 src/test/ui/suggestions/method-missing-parentheses.rs     | 2 +-
 src/test/ui/suggestions/method-missing-parentheses.stderr | 2 +-
 5 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/librustc_parse/parser/expr.rs b/src/librustc_parse/parser/expr.rs
index d98321416957d..56871c0c66379 100644
--- a/src/librustc_parse/parser/expr.rs
+++ b/src/librustc_parse/parser/expr.rs
@@ -828,7 +828,7 @@ impl<'a> Parser<'a> {
             if let Some(args) = segment.args {
                 self.struct_span_err(
                     args.span(),
-                    "field expressions may not have generic arguments",
+                    "field expressions cannot have generic arguments",
                 )
                 .emit();
             }
diff --git a/src/test/ui/parser/type-parameters-in-field-exprs.rs b/src/test/ui/parser/type-parameters-in-field-exprs.rs
index 6a3b2c1c60605..4cd77ebbd862f 100644
--- a/src/test/ui/parser/type-parameters-in-field-exprs.rs
+++ b/src/test/ui/parser/type-parameters-in-field-exprs.rs
@@ -9,9 +9,9 @@ fn main() {
         y: 2,
     };
     f.x::<isize>;
-    //~^ ERROR field expressions may not have generic arguments
+    //~^ ERROR field expressions cannot have generic arguments
     f.x::<>;
-    //~^ ERROR field expressions may not have generic arguments
+    //~^ ERROR field expressions cannot have generic arguments
     f.x::();
-    //~^ ERROR field expressions may not have generic arguments
+    //~^ ERROR field expressions cannot have generic arguments
 }
diff --git a/src/test/ui/parser/type-parameters-in-field-exprs.stderr b/src/test/ui/parser/type-parameters-in-field-exprs.stderr
index 306b4754d0d69..ce7364d3534f6 100644
--- a/src/test/ui/parser/type-parameters-in-field-exprs.stderr
+++ b/src/test/ui/parser/type-parameters-in-field-exprs.stderr
@@ -1,16 +1,16 @@
-error: field expressions may not have generic arguments
+error: field expressions cannot have generic arguments
   --> $DIR/type-parameters-in-field-exprs.rs:11:10
    |
 LL |     f.x::<isize>;
    |          ^^^^^^^
 
-error: field expressions may not have generic arguments
+error: field expressions cannot have generic arguments
   --> $DIR/type-parameters-in-field-exprs.rs:13:10
    |
 LL |     f.x::<>;
    |          ^^
 
-error: field expressions may not have generic arguments
+error: field expressions cannot have generic arguments
   --> $DIR/type-parameters-in-field-exprs.rs:15:7
    |
 LL |     f.x::();
diff --git a/src/test/ui/suggestions/method-missing-parentheses.rs b/src/test/ui/suggestions/method-missing-parentheses.rs
index e1a85271ad0a3..f10bfb56d2e12 100644
--- a/src/test/ui/suggestions/method-missing-parentheses.rs
+++ b/src/test/ui/suggestions/method-missing-parentheses.rs
@@ -1,5 +1,5 @@
 fn main() {
     let _ = vec![].into_iter().collect::<usize>;
     //~^ ERROR attempted to take value of method `collect` on type `std::vec::IntoIter<_>`
-    //~| ERROR field expressions may not have generic arguments
+    //~| ERROR field expressions cannot have generic arguments
 }
diff --git a/src/test/ui/suggestions/method-missing-parentheses.stderr b/src/test/ui/suggestions/method-missing-parentheses.stderr
index 8569eb6f4ad1e..6e4f7a84724bf 100644
--- a/src/test/ui/suggestions/method-missing-parentheses.stderr
+++ b/src/test/ui/suggestions/method-missing-parentheses.stderr
@@ -1,4 +1,4 @@
-error: field expressions may not have generic arguments
+error: field expressions cannot have generic arguments
   --> $DIR/method-missing-parentheses.rs:2:41
    |
 LL |     let _ = vec![].into_iter().collect::<usize>;

From b637c0e84a9dbb5883130e0ea1e5ee9e8acf3bc1 Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 11:47:26 -0800
Subject: [PATCH 14/34] Add initial debug fmt for Backtrace

---
 src/libstd/backtrace.rs | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index 5ba1c940251dc..6b4ae77cec77d 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -106,6 +106,7 @@ use backtrace_rs as backtrace;
 /// previous point in time. In some instances the `Backtrace` type may
 /// internally be empty due to configuration. For more information see
 /// `Backtrace::capture`.
+#[derive(Debug)]
 pub struct Backtrace {
     inner: Inner,
 }
@@ -126,12 +127,14 @@ pub enum BacktraceStatus {
     Captured,
 }
 
+#[derive(Debug)]
 enum Inner {
     Unsupported,
     Disabled,
     Captured(Mutex<Capture>),
 }
 
+#[derive(Debug)]
 struct Capture {
     actual_start: usize,
     resolved: bool,
@@ -143,11 +146,13 @@ fn _assert_send_sync() {
     _assert::<Backtrace>();
 }
 
+#[derive(Debug)]
 struct BacktraceFrame {
     frame: backtrace::Frame,
     symbols: Vec<BacktraceSymbol>,
 }
 
+#[derive(Debug)]
 struct BacktraceSymbol {
     name: Option<Vec<u8>>,
     filename: Option<BytesOrWide>,
@@ -159,6 +164,20 @@ enum BytesOrWide {
     Wide(Vec<u16>),
 }
 
+impl fmt::Debug for BytesOrWide {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        output_filename(
+            fmt,
+            match self {
+                BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
+                BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
+            },
+            backtrace::PrintFmt::Full,
+            crate::env::current_dir().as_ref().ok(),
+        )
+    }
+}
+
 impl Backtrace {
     /// Returns whether backtrace captures are enabled through environment
     /// variables.
@@ -267,12 +286,6 @@ impl Backtrace {
 }
 
 impl fmt::Display for Backtrace {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Debug::fmt(self, fmt)
-    }
-}
-
-impl fmt::Debug for Backtrace {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut capture = match &self.inner {
             Inner::Unsupported => return fmt.write_str("unsupported backtrace"),

From 49204563e13f57917cc22ac8f8b608927a432038 Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 13:15:03 -0800
Subject: [PATCH 15/34] Get vaguely working with a test for checking output

---
 src/libstd/backtrace.rs | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index 6b4ae77cec77d..f6c34486d7093 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -152,7 +152,6 @@ struct BacktraceFrame {
     symbols: Vec<BacktraceSymbol>,
 }
 
-#[derive(Debug)]
 struct BacktraceSymbol {
     name: Option<Vec<u8>>,
     filename: Option<BytesOrWide>,
@@ -164,6 +163,16 @@ enum BytesOrWide {
     Wide(Vec<u16>),
 }
 
+impl fmt::Debug for BacktraceSymbol {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct("BacktraceSymbol")
+            .field("name", &self.name.as_ref().map(|b| backtrace::SymbolName::new(b)))
+            .field("filename", &self.filename)
+            .field("lineno", &self.lineno)
+            .finish()
+    }
+}
+
 impl fmt::Debug for BytesOrWide {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         output_filename(
@@ -364,3 +373,19 @@ impl Capture {
         }
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn debug_backtrace_fmt() {
+        let bt = Backtrace::capture();
+        eprintln!("uncaptured: {:?}", bt);
+        let bt = Backtrace::force_capture();
+        eprintln!("captured: {:?}", bt);
+        eprintln!("display print: {}", bt);
+        eprintln!("resolved: {:?}", bt);
+        unimplemented!();
+    }
+}

From c0ba79eefd82d0a5614e295659b18f7b31e542a3 Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 15:15:13 -0800
Subject: [PATCH 16/34] less noisy format

---
 src/libstd/backtrace.rs | 44 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 37 insertions(+), 7 deletions(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index f6c34486d7093..87e6eafe47977 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -106,7 +106,6 @@ use backtrace_rs as backtrace;
 /// previous point in time. In some instances the `Backtrace` type may
 /// internally be empty due to configuration. For more information see
 /// `Backtrace::capture`.
-#[derive(Debug)]
 pub struct Backtrace {
     inner: Inner,
 }
@@ -146,7 +145,6 @@ fn _assert_send_sync() {
     _assert::<Backtrace>();
 }
 
-#[derive(Debug)]
 struct BacktraceFrame {
     frame: backtrace::Frame,
     symbols: Vec<BacktraceSymbol>,
@@ -163,13 +161,45 @@ enum BytesOrWide {
     Wide(Vec<u16>),
 }
 
+impl fmt::Debug for Backtrace {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut capture = match &self.inner {
+            Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
+            Inner::Disabled => return fmt.write_str("disabled backtrace"),
+            Inner::Captured(c) => c.lock().unwrap(),
+        };
+        capture.resolve();
+
+        let mut dbg = fmt.debug_list();
+
+        for frame in &capture.frames {
+            dbg.entries(&frame.symbols);
+        }
+
+        dbg.finish()
+    }
+}
+
+impl fmt::Debug for BacktraceFrame {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_list().entries(&self.symbols).finish()
+    }
+}
+
 impl fmt::Debug for BacktraceSymbol {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt.debug_struct("BacktraceSymbol")
-            .field("name", &self.name.as_ref().map(|b| backtrace::SymbolName::new(b)))
-            .field("filename", &self.filename)
-            .field("lineno", &self.lineno)
-            .finish()
+        let mut dbg = fmt.debug_struct("");
+        dbg.field("fn", &self.name.as_ref().map(|b| backtrace::SymbolName::new(b)));
+
+        if let Some(fname) = self.filename.as_ref() {
+            dbg.field("file", fname);
+        }
+
+        if let Some(line) = self.lineno.as_ref() {
+            dbg.field("line", &self.lineno);
+        }
+
+        dbg.finish()
     }
 }
 

From 0d5444ffa6ac0447849627406d15d16630a6364b Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 15:16:24 -0800
Subject: [PATCH 17/34] remove unnecessary derives

---
 src/libstd/backtrace.rs | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index 87e6eafe47977..571c13241b53a 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -126,14 +126,12 @@ pub enum BacktraceStatus {
     Captured,
 }
 
-#[derive(Debug)]
 enum Inner {
     Unsupported,
     Disabled,
     Captured(Mutex<Capture>),
 }
 
-#[derive(Debug)]
 struct Capture {
     actual_start: usize,
     resolved: bool,

From 76e6d6fe114944c88bea77baf700aa5ead2aa9e3 Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 15:17:40 -0800
Subject: [PATCH 18/34] remove unnecessary Debug impl for BacktraceFrame

---
 src/libstd/backtrace.rs | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index 571c13241b53a..b3d26890fdd87 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -178,12 +178,6 @@ impl fmt::Debug for Backtrace {
     }
 }
 
-impl fmt::Debug for BacktraceFrame {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt.debug_list().entries(&self.symbols).finish()
-    }
-}
-
 impl fmt::Debug for BacktraceSymbol {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut dbg = fmt.debug_struct("");

From 583dd2c3eebafb72ec89fd4497c3cb751e2343ba Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 15:18:29 -0800
Subject: [PATCH 19/34] make it compile

---
 src/libstd/backtrace.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index b3d26890fdd87..63669532ebc03 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -188,7 +188,7 @@ impl fmt::Debug for BacktraceSymbol {
         }
 
         if let Some(line) = self.lineno.as_ref() {
-            dbg.field("line", &self.lineno);
+            dbg.field("line", line);
         }
 
         dbg.finish()

From 87117783fb59a580d0a90200ac62ecf219142e49 Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 15:39:32 -0800
Subject: [PATCH 20/34] final format cleanups

---
 src/libstd/backtrace.rs | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index 63669532ebc03..46ea719b2ad41 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -168,6 +168,8 @@ impl fmt::Debug for Backtrace {
         };
         capture.resolve();
 
+        write!(fmt, "Backtrace ")?;
+
         let mut dbg = fmt.debug_list();
 
         for frame in &capture.frames {
@@ -181,7 +183,12 @@ impl fmt::Debug for Backtrace {
 impl fmt::Debug for BacktraceSymbol {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut dbg = fmt.debug_struct("");
-        dbg.field("fn", &self.name.as_ref().map(|b| backtrace::SymbolName::new(b)));
+
+        if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
+            dbg.field("fn", &fn_name);
+        } else {
+            dbg.field("fn", &"<unknown>");
+        }
 
         if let Some(fname) = self.filename.as_ref() {
             dbg.field("file", fname);

From 70c91330143b7979ec2847d0016ece75053e5d39 Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 15:48:09 -0800
Subject: [PATCH 21/34] remove Some from fn name

---
 src/libstd/backtrace.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index 46ea719b2ad41..d5a7d6b8a9406 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -185,7 +185,7 @@ impl fmt::Debug for BacktraceSymbol {
         let mut dbg = fmt.debug_struct("");
 
         if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
-            dbg.field("fn", &fn_name);
+            dbg.field("fn", &format_args!("\"{}\"", fn_name));
         } else {
             dbg.field("fn", &"<unknown>");
         }

From 230ed3ea75a18984a0e34fb99dae69e8aa779c64 Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 17:28:04 -0800
Subject: [PATCH 22/34] use debug_map and skip empty frames

---
 src/libstd/backtrace.rs | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index d5a7d6b8a9406..d481f227db73e 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -173,6 +173,10 @@ impl fmt::Debug for Backtrace {
         let mut dbg = fmt.debug_list();
 
         for frame in &capture.frames {
+            if frame.frame.ip().is_null() {
+                continue;
+            }
+
             dbg.entries(&frame.symbols);
         }
 
@@ -182,20 +186,20 @@ impl fmt::Debug for Backtrace {
 
 impl fmt::Debug for BacktraceSymbol {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut dbg = fmt.debug_struct("");
+        let mut dbg = fmt.debug_map();
 
         if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
-            dbg.field("fn", &format_args!("\"{}\"", fn_name));
+            dbg.entry(&"fn", &format_args!("\"{}\"", fn_name));
         } else {
-            dbg.field("fn", &"<unknown>");
+            dbg.entry(&"fn", &"<unknown>");
         }
 
         if let Some(fname) = self.filename.as_ref() {
-            dbg.field("file", fname);
+            dbg.entry(&"file", fname);
         }
 
         if let Some(line) = self.lineno.as_ref() {
-            dbg.field("line", line);
+            dbg.entry(&"line", line);
         }
 
         dbg.finish()
@@ -415,6 +419,7 @@ mod tests {
         eprintln!("captured: {:?}", bt);
         eprintln!("display print: {}", bt);
         eprintln!("resolved: {:?}", bt);
+        eprintln!("resolved alt: {:#?}", bt);
         unimplemented!();
     }
 }

From de25048a23bbec9ee0dc2f9485e45514444a0d42 Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 17:42:04 -0800
Subject: [PATCH 23/34] add nice alt fmt for debug

---
 src/libstd/backtrace.rs | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index d481f227db73e..7ca7ab674ba3f 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -186,23 +186,23 @@ impl fmt::Debug for Backtrace {
 
 impl fmt::Debug for BacktraceSymbol {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut dbg = fmt.debug_map();
+        write!(fmt, "{{ ")?;
 
         if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
-            dbg.entry(&"fn", &format_args!("\"{}\"", fn_name));
+            write!(fmt, "fn: \"{:?}\"", fn_name)?;
         } else {
-            dbg.entry(&"fn", &"<unknown>");
+            write!(fmt, "fn: \"<unknown>\"")?;
         }
 
         if let Some(fname) = self.filename.as_ref() {
-            dbg.entry(&"file", fname);
+            write!(fmt, ", file: {:?}", fname)?;
         }
 
         if let Some(line) = self.lineno.as_ref() {
-            dbg.entry(&"line", line);
+            write!(fmt, ", line: {:?}", line)?;
         }
 
-        dbg.finish()
+        write!(fmt, " }}")
     }
 }
 

From 192b10391784de14e8cc672314e3b68e9c450fce Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 17:45:58 -0800
Subject: [PATCH 24/34] make symbol printing consistent with backtrace_rs

---
 src/libstd/backtrace.rs | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index 7ca7ab674ba3f..b82a44350cc8a 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -189,9 +189,10 @@ impl fmt::Debug for BacktraceSymbol {
         write!(fmt, "{{ ")?;
 
         if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
-            write!(fmt, "fn: \"{:?}\"", fn_name)?;
+            write!(fmt, "fn: ")?;
+            fmt::Display::fmt(&fn_name, fmt)?;
         } else {
-            write!(fmt, "fn: \"<unknown>\"")?;
+            write!(fmt, "fn: <unknown>")?;
         }
 
         if let Some(fname) = self.filename.as_ref() {

From 7064a0ec59005f1e67e89a794ff70d687d2d7041 Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 21:07:36 -0800
Subject: [PATCH 25/34] maximum alternative consistency!

---
 src/libstd/backtrace.rs | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index b82a44350cc8a..448b988d99c1c 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -168,11 +168,17 @@ impl fmt::Debug for Backtrace {
         };
         capture.resolve();
 
+        let frames = if fmt.alternate() {
+            &capture.frames[..]
+        } else {
+            &capture.frames[capture.actual_start..]
+        };
+
         write!(fmt, "Backtrace ")?;
 
         let mut dbg = fmt.debug_list();
 
-        for frame in &capture.frames {
+        for frame in frames {
             if frame.frame.ip().is_null() {
                 continue;
             }
@@ -215,7 +221,7 @@ impl fmt::Debug for BytesOrWide {
                 BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                 BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
             },
-            backtrace::PrintFmt::Full,
+            if fmt.alternate() { backtrace::PrintFmt::Full } else { backtrace::PrintFmt::Short },
             crate::env::current_dir().as_ref().ok(),
         )
     }
@@ -419,6 +425,7 @@ mod tests {
         let bt = Backtrace::force_capture();
         eprintln!("captured: {:?}", bt);
         eprintln!("display print: {}", bt);
+        eprintln!("display print alt: {:#}", bt);
         eprintln!("resolved: {:?}", bt);
         eprintln!("resolved alt: {:#?}", bt);
         unimplemented!();

From 6797bfd203dea6601548098214504375ad0e45ac Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 21:38:59 -0800
Subject: [PATCH 26/34] rule over the code in libstd with an iron fist

---
 src/libstd/backtrace.rs | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index 448b988d99c1c..391d22df5e51e 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -168,11 +168,7 @@ impl fmt::Debug for Backtrace {
         };
         capture.resolve();
 
-        let frames = if fmt.alternate() {
-            &capture.frames[..]
-        } else {
-            &capture.frames[capture.actual_start..]
-        };
+        let frames = &capture.frames[capture.actual_start..];
 
         write!(fmt, "Backtrace ")?;
 
@@ -195,10 +191,9 @@ impl fmt::Debug for BacktraceSymbol {
         write!(fmt, "{{ ")?;
 
         if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
-            write!(fmt, "fn: ")?;
-            fmt::Display::fmt(&fn_name, fmt)?;
+            write!(fmt, "fn: \"{}\"", fn_name)?;
         } else {
-            write!(fmt, "fn: <unknown>")?;
+            write!(fmt, "fn: \"<unknown>\"")?;
         }
 
         if let Some(fname) = self.filename.as_ref() {
@@ -221,7 +216,7 @@ impl fmt::Debug for BytesOrWide {
                 BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                 BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
             },
-            if fmt.alternate() { backtrace::PrintFmt::Full } else { backtrace::PrintFmt::Short },
+            backtrace::PrintFmt::Short,
             crate::env::current_dir().as_ref().ok(),
         )
     }

From c8817aa521092b02d4b9e8494429e178259e506a Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Mon, 10 Feb 2020 21:54:27 -0800
Subject: [PATCH 27/34] backwards again, god damnit

---
 src/libstd/backtrace.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index 391d22df5e51e..4b47a8cf16923 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -191,7 +191,7 @@ impl fmt::Debug for BacktraceSymbol {
         write!(fmt, "{{ ")?;
 
         if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
-            write!(fmt, "fn: \"{}\"", fn_name)?;
+            write!(fmt, "fn: \"{:#}\"", fn_name)?;
         } else {
             write!(fmt, "fn: \"<unknown>\"")?;
         }

From ec8ee7fb81c208fbd0fe53f11b1c792f3e0d6c6f Mon Sep 17 00:00:00 2001
From: Jane Lusby <jlusby@yaah.dev>
Date: Tue, 11 Feb 2020 08:39:27 -0800
Subject: [PATCH 28/34] remove intentionally failing test

---
 src/libstd/backtrace.rs | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/src/libstd/backtrace.rs b/src/libstd/backtrace.rs
index 4b47a8cf16923..a1c9aa75d779a 100644
--- a/src/libstd/backtrace.rs
+++ b/src/libstd/backtrace.rs
@@ -408,21 +408,3 @@ impl Capture {
         }
     }
 }
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn debug_backtrace_fmt() {
-        let bt = Backtrace::capture();
-        eprintln!("uncaptured: {:?}", bt);
-        let bt = Backtrace::force_capture();
-        eprintln!("captured: {:?}", bt);
-        eprintln!("display print: {}", bt);
-        eprintln!("display print alt: {:#}", bt);
-        eprintln!("resolved: {:?}", bt);
-        eprintln!("resolved alt: {:#?}", bt);
-        unimplemented!();
-    }
-}

From ee85e913a2efc3485634a9425881cc106cb85c21 Mon Sep 17 00:00:00 2001
From: Tyler Mandry <tmandry@gmail.com>
Date: Tue, 11 Feb 2020 22:25:32 -0800
Subject: [PATCH 29/34] Update compiler-builtins to 0.1.25

---
 Cargo.lock | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index f15f81e76e1cb..98950808430f1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -576,9 +576,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.24"
+version = "0.1.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9975aefa63997ef75ca9cf013ff1bb81487aaa0b622c21053afd3b92979a7af"
+checksum = "438ac08ddc5efe81452f984a9e33ba425b00b31d1f48e6acd9e2210aa28cc52e"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",

From 03a73fa2cf5688a12fa5557170945a2a7c27436e Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Sun, 5 Jan 2020 22:32:15 +0100
Subject: [PATCH 30/34] Use IRBuilder to create memset

To avoid creating memsets with outdated signature. For some reason
SROA chokes on this when using NewPM.
---
 src/librustc_codegen_llvm/builder.rs  | 17 +++++++++++------
 src/librustc_codegen_llvm/context.rs  |  4 ----
 src/librustc_codegen_llvm/llvm/ffi.rs |  8 ++++++++
 src/rustllvm/RustWrapper.cpp          |  8 ++++++++
 4 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 342ac437d3c24..f00460164daec 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -781,13 +781,18 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         align: Align,
         flags: MemFlags,
     ) {
-        let ptr_width = &self.sess().target.target.target_pointer_width;
-        let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width);
-        let llintrinsicfn = self.get_intrinsic(&intrinsic_key);
+        let is_volatile = flags.contains(MemFlags::VOLATILE);
         let ptr = self.pointercast(ptr, self.type_i8p());
-        let align = self.const_u32(align.bytes() as u32);
-        let volatile = self.const_bool(flags.contains(MemFlags::VOLATILE));
-        self.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None);
+        unsafe {
+            llvm::LLVMRustBuildMemSet(
+                self.llbuilder,
+                ptr,
+                align.bytes() as c_uint,
+                fill_byte,
+                size,
+                is_volatile,
+            );
+        }
     }
 
     fn select(
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 6b31f14410d2f..9f5c8736efc0c 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -562,10 +562,6 @@ impl CodegenCx<'b, 'tcx> {
             t_v8f64: t_f64, 8;
         }
 
-        ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void);
-        ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
-        ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void);
-
         ifn!("llvm.trap", fn() -> void);
         ifn!("llvm.debugtrap", fn() -> void);
         ifn!("llvm.frameaddress", fn(t_i32) -> i8p);
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index 146b7d3d76c5e..cdb55b179a3a2 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -1315,6 +1315,14 @@ extern "C" {
         Size: &'a Value,
         IsVolatile: bool,
     ) -> &'a Value;
+    pub fn LLVMRustBuildMemSet(
+        B: &Builder<'a>,
+        Dst: &'a Value,
+        DstAlign: c_uint,
+        Val: &'a Value,
+        Size: &'a Value,
+        IsVolatile: bool,
+    ) -> &'a Value;
     pub fn LLVMBuildSelect(
         B: &Builder<'a>,
         If: &'a Value,
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 46e467011b91a..49b6e1bfec38d 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -1296,6 +1296,14 @@ extern "C" LLVMValueRef LLVMRustBuildMemMove(LLVMBuilderRef B,
 #endif
 }
 
+extern "C" LLVMValueRef LLVMRustBuildMemSet(LLVMBuilderRef B,
+                                            LLVMValueRef Dst, unsigned DstAlign,
+                                            LLVMValueRef Val,
+                                            LLVMValueRef Size, bool IsVolatile) {
+  return wrap(unwrap(B)->CreateMemSet(
+      unwrap(Dst), unwrap(Val), unwrap(Size), DstAlign, IsVolatile));
+}
+
 extern "C" LLVMValueRef
 LLVMRustBuildInvoke(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
                     unsigned NumArgs, LLVMBasicBlockRef Then,

From 737f08bc28363626cf4036f646cb182b61d05bd3 Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Sun, 5 Jan 2020 23:27:05 +0100
Subject: [PATCH 31/34] Fix mangled names of lifetime intrinsics

---
 src/librustc_codegen_llvm/builder.rs | 4 ++--
 src/librustc_codegen_llvm/context.rs | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index f00460164daec..ab6c55becdb02 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -990,11 +990,11 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
     }
 
     fn lifetime_start(&mut self, ptr: &'ll Value, size: Size) {
-        self.call_lifetime_intrinsic("llvm.lifetime.start", ptr, size);
+        self.call_lifetime_intrinsic("llvm.lifetime.start.p0i8", ptr, size);
     }
 
     fn lifetime_end(&mut self, ptr: &'ll Value, size: Size) {
-        self.call_lifetime_intrinsic("llvm.lifetime.end", ptr, size);
+        self.call_lifetime_intrinsic("llvm.lifetime.end.p0i8", ptr, size);
     }
 
     fn call(
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 9f5c8736efc0c..46f461b98c8de 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -826,8 +826,8 @@ impl CodegenCx<'b, 'tcx> {
         ifn!("llvm.usub.sat.i64", fn(t_i64, t_i64) -> t_i64);
         ifn!("llvm.usub.sat.i128", fn(t_i128, t_i128) -> t_i128);
 
-        ifn!("llvm.lifetime.start", fn(t_i64, i8p) -> void);
-        ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void);
+        ifn!("llvm.lifetime.start.p0i8", fn(t_i64, i8p) -> void);
+        ifn!("llvm.lifetime.end.p0i8", fn(t_i64, i8p) -> void);
 
         ifn!("llvm.expect.i1", fn(i1, i1) -> i1);
         ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32);

From c6b0803202c95abd614c8ea448f7c7ff948da31a Mon Sep 17 00:00:00 2001
From: Nikita Popov <nikita.ppv@gmail.com>
Date: Sun, 5 Jan 2020 19:16:58 +0100
Subject: [PATCH 32/34] Add support for new pass manager

The new pass manager can be enabled using
-Z new-llvm-pass-manager=on.
---
 src/librustc_codegen_llvm/back/lto.rs         |  14 +
 src/librustc_codegen_llvm/back/write.rs       | 125 +++++++--
 src/librustc_codegen_llvm/llvm/ffi.rs         |  49 ++++
 src/librustc_codegen_ssa/back/write.rs        |   3 +
 src/librustc_session/options.rs               |   2 +
 src/rustllvm/PassWrapper.cpp                  | 244 +++++++++++++++++-
 .../codegen/sanitizer-memory-track-orgins.rs  |   8 +-
 7 files changed, 422 insertions(+), 23 deletions(-)

diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs
index 76a6ffbb1c5b2..e3d69fc5c76df 100644
--- a/src/librustc_codegen_llvm/back/lto.rs
+++ b/src/librustc_codegen_llvm/back/lto.rs
@@ -584,6 +584,20 @@ pub(crate) fn run_pass_manager(
     //      tools/lto/LTOCodeGenerator.cpp
     debug!("running the pass manager");
     unsafe {
+        if write::should_use_new_llvm_pass_manager(config) {
+            let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
+            let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
+            // See comment below for why this is necessary.
+            let opt_level = if let config::OptLevel::No = opt_level {
+                config::OptLevel::Less
+            } else {
+                opt_level
+            };
+            write::optimize_with_new_llvm_pass_manager(module, config, opt_level, opt_stage);
+            debug!("lto done");
+            return;
+        }
+
         let pm = llvm::LLVMCreatePassManager();
         llvm::LLVMAddAnalysisPasses(module.module_llvm.tm, pm);
 
diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs
index 7dd57da90c3d6..9008970847a59 100644
--- a/src/librustc_codegen_llvm/back/write.rs
+++ b/src/librustc_codegen_llvm/back/write.rs
@@ -111,6 +111,18 @@ pub fn to_llvm_opt_settings(
     }
 }
 
+fn to_pass_builder_opt_level(cfg: config::OptLevel) -> llvm::PassBuilderOptLevel {
+    use config::OptLevel::*;
+    match cfg {
+        No => llvm::PassBuilderOptLevel::O0,
+        Less => llvm::PassBuilderOptLevel::O1,
+        Default => llvm::PassBuilderOptLevel::O2,
+        Aggressive => llvm::PassBuilderOptLevel::O3,
+        Size => llvm::PassBuilderOptLevel::Os,
+        SizeMin => llvm::PassBuilderOptLevel::Oz,
+    }
+}
+
 // If find_features is true this won't access `sess.crate_types` by assuming
 // that `is_pie_binary` is false. When we discover LLVM target features
 // `sess.crate_types` is uninitialized so we cannot access it.
@@ -303,6 +315,88 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
     }
 }
 
+fn get_pgo_gen_path(config: &ModuleConfig) -> Option<CString> {
+    match config.pgo_gen {
+        SwitchWithOptPath::Enabled(ref opt_dir_path) => {
+            let path = if let Some(dir_path) = opt_dir_path {
+                dir_path.join("default_%m.profraw")
+            } else {
+                PathBuf::from("default_%m.profraw")
+            };
+
+            Some(CString::new(format!("{}", path.display())).unwrap())
+        }
+        SwitchWithOptPath::Disabled => None,
+    }
+}
+
+fn get_pgo_use_path(config: &ModuleConfig) -> Option<CString> {
+    config
+        .pgo_use
+        .as_ref()
+        .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap())
+}
+
+pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool {
+    // We only support the new pass manager starting with LLVM 9.
+    if llvm_util::get_major_version() < 9 {
+        return false;
+    }
+
+    // The new pass manager is disabled by default.
+    config.new_llvm_pass_manager.unwrap_or(false)
+}
+
+pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
+    module: &ModuleCodegen<ModuleLlvm>,
+    config: &ModuleConfig,
+    opt_level: config::OptLevel,
+    opt_stage: llvm::OptStage,
+) {
+    let unroll_loops =
+        opt_level != config::OptLevel::Size && opt_level != config::OptLevel::SizeMin;
+    let using_thin_buffers = opt_stage == llvm::OptStage::PreLinkThinLTO || config.bitcode_needed();
+    let pgo_gen_path = get_pgo_gen_path(config);
+    let pgo_use_path = get_pgo_use_path(config);
+    let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO;
+    // Sanitizer instrumentation is only inserted during the pre-link optimization stage.
+    let sanitizer_options = if !is_lto {
+        config.sanitizer.as_ref().map(|s| llvm::SanitizerOptions {
+            sanitize_memory: *s == Sanitizer::Memory,
+            sanitize_thread: *s == Sanitizer::Thread,
+            sanitize_address: *s == Sanitizer::Address,
+            sanitize_recover: config.sanitizer_recover.contains(s),
+            sanitize_memory_track_origins: config.sanitizer_memory_track_origins as c_int,
+        })
+    } else {
+        None
+    };
+
+    // FIXME: NewPM doesn't provide a facility to pass custom InlineParams.
+    // We would have to add upstream support for this first, before we can support
+    // config.inline_threshold and our more aggressive default thresholds.
+    // FIXME: NewPM uses an different and more explicit way to textually represent
+    // pass pipelines. It would probably make sense to expose this, but it would
+    // require a different format than the current -C passes.
+    llvm::LLVMRustOptimizeWithNewPassManager(
+        module.module_llvm.llmod(),
+        &*module.module_llvm.tm,
+        to_pass_builder_opt_level(opt_level),
+        opt_stage,
+        config.no_prepopulate_passes,
+        config.verify_llvm_ir,
+        using_thin_buffers,
+        config.merge_functions,
+        unroll_loops,
+        config.vectorize_slp,
+        config.vectorize_loop,
+        config.no_builtins,
+        sanitizer_options.as_ref(),
+        pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
+        pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
+    );
+}
+
 // Unsafe due to LLVM calls.
 pub(crate) unsafe fn optimize(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
@@ -327,6 +421,17 @@ pub(crate) unsafe fn optimize(
     }
 
     if let Some(opt_level) = config.opt_level {
+        if should_use_new_llvm_pass_manager(config) {
+            let opt_stage = match cgcx.lto {
+                Lto::Fat => llvm::OptStage::PreLinkFatLTO,
+                Lto::Thin | Lto::ThinLocal => llvm::OptStage::PreLinkThinLTO,
+                _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
+                _ => llvm::OptStage::PreLinkNoLTO,
+            };
+            optimize_with_new_llvm_pass_manager(module, config, opt_level, opt_stage);
+            return Ok(());
+        }
+
         // Create the two optimizing pass managers. These mirror what clang
         // does, and are by populated by LLVM's default PassManagerBuilder.
         // Each manager has a different set of passes, but they also share
@@ -757,24 +862,8 @@ pub unsafe fn with_llvm_pmb(
     let opt_size =
         config.opt_size.map(|x| to_llvm_opt_settings(x).1).unwrap_or(llvm::CodeGenOptSizeNone);
     let inline_threshold = config.inline_threshold;
-
-    let pgo_gen_path = match config.pgo_gen {
-        SwitchWithOptPath::Enabled(ref opt_dir_path) => {
-            let path = if let Some(dir_path) = opt_dir_path {
-                dir_path.join("default_%m.profraw")
-            } else {
-                PathBuf::from("default_%m.profraw")
-            };
-
-            Some(CString::new(format!("{}", path.display())).unwrap())
-        }
-        SwitchWithOptPath::Disabled => None,
-    };
-
-    let pgo_use_path = config
-        .pgo_use
-        .as_ref()
-        .map(|path_buf| CString::new(path_buf.to_string_lossy().as_bytes()).unwrap());
+    let pgo_gen_path = get_pgo_gen_path(config);
+    let pgo_use_path = get_pgo_use_path(config);
 
     llvm::LLVMRustConfigurePassManagerBuilder(
         builder,
diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/src/librustc_codegen_llvm/llvm/ffi.rs
index cdb55b179a3a2..f570e808f56f4 100644
--- a/src/librustc_codegen_llvm/llvm/ffi.rs
+++ b/src/librustc_codegen_llvm/llvm/ffi.rs
@@ -402,6 +402,38 @@ pub enum CodeGenOptLevel {
     Aggressive,
 }
 
+/// LLVMRustPassBuilderOptLevel
+#[repr(C)]
+pub enum PassBuilderOptLevel {
+    O0,
+    O1,
+    O2,
+    O3,
+    Os,
+    Oz,
+}
+
+/// LLVMRustOptStage
+#[derive(PartialEq)]
+#[repr(C)]
+pub enum OptStage {
+    PreLinkNoLTO,
+    PreLinkThinLTO,
+    PreLinkFatLTO,
+    ThinLTO,
+    FatLTO,
+}
+
+/// LLVMRustSanitizerOptions
+#[repr(C)]
+pub struct SanitizerOptions {
+    pub sanitize_memory: bool,
+    pub sanitize_thread: bool,
+    pub sanitize_address: bool,
+    pub sanitize_recover: bool,
+    pub sanitize_memory_track_origins: c_int,
+}
+
 /// LLVMRelocMode
 #[derive(Copy, Clone, PartialEq)]
 #[repr(C)]
@@ -1896,6 +1928,23 @@ extern "C" {
         Output: *const c_char,
         FileType: FileType,
     ) -> LLVMRustResult;
+    pub fn LLVMRustOptimizeWithNewPassManager(
+        M: &'a Module,
+        TM: &'a TargetMachine,
+        OptLevel: PassBuilderOptLevel,
+        OptStage: OptStage,
+        NoPrepopulatePasses: bool,
+        VerifyIR: bool,
+        UseThinLTOBuffers: bool,
+        MergeFunctions: bool,
+        UnrollLoops: bool,
+        SLPVectorize: bool,
+        LoopVectorize: bool,
+        DisableSimplifyLibCalls: bool,
+        SanitizerOptions: Option<&SanitizerOptions>,
+        PGOGenPath: *const c_char,
+        PGOUsePath: *const c_char,
+    );
     pub fn LLVMRustPrintModule(
         M: &'a Module,
         Output: *const c_char,
diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs
index 9905b3a56c0fa..92f795acc5438 100644
--- a/src/librustc_codegen_ssa/back/write.rs
+++ b/src/librustc_codegen_ssa/back/write.rs
@@ -88,6 +88,7 @@ pub struct ModuleConfig {
     pub vectorize_slp: bool,
     pub merge_functions: bool,
     pub inline_threshold: Option<usize>,
+    pub new_llvm_pass_manager: Option<bool>,
     // Instead of creating an object file by doing LLVM codegen, just
     // make the object file bitcode. Provides easy compatibility with
     // emscripten's ecc compiler, when used as the linker.
@@ -132,6 +133,7 @@ impl ModuleConfig {
             vectorize_slp: false,
             merge_functions: false,
             inline_threshold: None,
+            new_llvm_pass_manager: None,
         }
     }
 
@@ -140,6 +142,7 @@ impl ModuleConfig {
         self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes;
         self.no_builtins = no_builtins || sess.target.target.options.no_builtins;
         self.inline_threshold = sess.opts.cg.inline_threshold;
+        self.new_llvm_pass_manager = sess.opts.debugging_opts.new_llvm_pass_manager;
         self.obj_is_bitcode =
             sess.target.target.options.obj_is_bitcode || sess.opts.cg.linker_plugin_lto.enabled();
         let embed_bitcode =
diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs
index 4b3645cce723a..a794670d7b8fe 100644
--- a/src/librustc_session/options.rs
+++ b/src/librustc_session/options.rs
@@ -968,4 +968,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "compile without linking"),
     link_only: bool = (false, parse_bool, [TRACKED],
         "link the `.rlink` file generated by `-Z no-link`"),
+    new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED],
+        "use new LLVM pass manager"),
 }
diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp
index 4ac7e0e6e1fc0..15e2251d76321 100644
--- a/src/rustllvm/PassWrapper.cpp
+++ b/src/rustllvm/PassWrapper.cpp
@@ -12,6 +12,11 @@
 #include "llvm/IR/AutoUpgrade.h"
 #include "llvm/IR/AssemblyAnnotationWriter.h"
 #include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Verifier.h"
+#include "llvm/Passes/PassBuilder.h"
+#if LLVM_VERSION_GE(9, 0)
+#include "llvm/Passes/StandardInstrumentations.h"
+#endif
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Host.h"
@@ -32,9 +37,12 @@
 #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h"
 #include "llvm/Transforms/Instrumentation/MemorySanitizer.h"
 #endif
+#if LLVM_VERSION_GE(9, 0)
+#include "llvm/Transforms/Utils/CanonicalizeAliases.h"
+#endif
+#include "llvm/Transforms/Utils/NameAnonGlobals.h"
 
 using namespace llvm;
-using namespace llvm::legacy;
 
 typedef struct LLVMOpaquePass *LLVMPassRef;
 typedef struct LLVMOpaqueTargetMachine *LLVMTargetMachineRef;
@@ -314,6 +322,34 @@ static CodeGenOpt::Level fromRust(LLVMRustCodeGenOptLevel Level) {
   }
 }
 
+enum class LLVMRustPassBuilderOptLevel {
+  O0,
+  O1,
+  O2,
+  O3,
+  Os,
+  Oz,
+};
+
+static PassBuilder::OptimizationLevel fromRust(LLVMRustPassBuilderOptLevel Level) {
+  switch (Level) {
+  case LLVMRustPassBuilderOptLevel::O0:
+    return PassBuilder::O0;
+  case LLVMRustPassBuilderOptLevel::O1:
+    return PassBuilder::O1;
+  case LLVMRustPassBuilderOptLevel::O2:
+    return PassBuilder::O2;
+  case LLVMRustPassBuilderOptLevel::O3:
+    return PassBuilder::O3;
+  case LLVMRustPassBuilderOptLevel::Os:
+    return PassBuilder::Os;
+  case LLVMRustPassBuilderOptLevel::Oz:
+    return PassBuilder::Oz;
+  default:
+    report_fatal_error("Bad PassBuilderOptLevel.");
+  }
+}
+
 enum class LLVMRustRelocMode {
   Default,
   Static,
@@ -604,6 +640,212 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR,
   return LLVMRustResult::Success;
 }
 
+enum class LLVMRustOptStage {
+  PreLinkNoLTO,
+  PreLinkThinLTO,
+  PreLinkFatLTO,
+  ThinLTO,
+  FatLTO,
+};
+
+struct LLVMRustSanitizerOptions {
+  bool SanitizeMemory;
+  bool SanitizeThread;
+  bool SanitizeAddress;
+  bool SanitizeRecover;
+  int SanitizeMemoryTrackOrigins;
+};
+
+extern "C" void
+LLVMRustOptimizeWithNewPassManager(
+    LLVMModuleRef ModuleRef,
+    LLVMTargetMachineRef TMRef,
+    LLVMRustPassBuilderOptLevel OptLevelRust,
+    LLVMRustOptStage OptStage,
+    bool NoPrepopulatePasses, bool VerifyIR, bool UseThinLTOBuffers,
+    bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize,
+    bool DisableSimplifyLibCalls,
+    LLVMRustSanitizerOptions *SanitizerOptions,
+    const char *PGOGenPath, const char *PGOUsePath) {
+#if LLVM_VERSION_GE(9, 0)
+  Module *TheModule = unwrap(ModuleRef);
+  TargetMachine *TM = unwrap(TMRef);
+  PassBuilder::OptimizationLevel OptLevel = fromRust(OptLevelRust);
+
+  // FIXME: MergeFunctions is not supported by NewPM yet.
+  (void) MergeFunctions;
+
+  PipelineTuningOptions PTO;
+  PTO.LoopUnrolling = UnrollLoops;
+  PTO.LoopInterleaving = UnrollLoops;
+  PTO.LoopVectorization = LoopVectorize;
+  PTO.SLPVectorization = SLPVectorize;
+
+  PassInstrumentationCallbacks PIC;
+  StandardInstrumentations SI;
+  SI.registerCallbacks(PIC);
+
+  Optional<PGOOptions> PGOOpt;
+  if (PGOGenPath) {
+    assert(!PGOUsePath);
+    PGOOpt = PGOOptions(PGOGenPath, "", "", PGOOptions::IRInstr);
+  } else if (PGOUsePath) {
+    assert(!PGOGenPath);
+    PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse);
+  }
+
+  PassBuilder PB(TM, PTO, PGOOpt, &PIC);
+
+  // FIXME: We may want to expose this as an option.
+  bool DebugPassManager = false;
+  LoopAnalysisManager LAM(DebugPassManager);
+  FunctionAnalysisManager FAM(DebugPassManager);
+  CGSCCAnalysisManager CGAM(DebugPassManager);
+  ModuleAnalysisManager MAM(DebugPassManager);
+
+  FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); });
+
+  Triple TargetTriple(TheModule->getTargetTriple());
+  std::unique_ptr<TargetLibraryInfoImpl> TLII(new TargetLibraryInfoImpl(TargetTriple));
+  if (DisableSimplifyLibCalls)
+    TLII->disableAllFunctions();
+  FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
+
+  PB.registerModuleAnalyses(MAM);
+  PB.registerCGSCCAnalyses(CGAM);
+  PB.registerFunctionAnalyses(FAM);
+  PB.registerLoopAnalyses(LAM);
+  PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
+
+  // We manually collect pipeline callbacks so we can apply them at O0, where the
+  // PassBuilder does not create a pipeline.
+  std::vector<std::function<void(ModulePassManager &)>> PipelineStartEPCallbacks;
+  std::vector<std::function<void(FunctionPassManager &, PassBuilder::OptimizationLevel)>>
+      OptimizerLastEPCallbacks;
+
+  if (VerifyIR) {
+    PipelineStartEPCallbacks.push_back([VerifyIR](ModulePassManager &MPM) {
+        MPM.addPass(VerifierPass());
+    });
+  }
+
+  if (SanitizerOptions) {
+    if (SanitizerOptions->SanitizeMemory) {
+      MemorySanitizerOptions Options(
+          SanitizerOptions->SanitizeMemoryTrackOrigins,
+          SanitizerOptions->SanitizeRecover,
+          /*CompileKernel=*/false);
+#if LLVM_VERSION_GE(10, 0)
+      PipelineStartEPCallbacks.push_back([Options](ModulePassManager &MPM) {
+        MPM.addPass(MemorySanitizerPass(Options));
+      });
+#endif
+      OptimizerLastEPCallbacks.push_back(
+        [Options](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
+          FPM.addPass(MemorySanitizerPass(Options));
+        }
+      );
+    }
+
+    if (SanitizerOptions->SanitizeThread) {
+#if LLVM_VERSION_GE(10, 0)
+      PipelineStartEPCallbacks.push_back([](ModulePassManager &MPM) {
+        MPM.addPass(ThreadSanitizerPass());
+      });
+#endif
+      OptimizerLastEPCallbacks.push_back(
+        [](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
+          FPM.addPass(ThreadSanitizerPass());
+        }
+      );
+    }
+
+    if (SanitizerOptions->SanitizeAddress) {
+      // FIXME: Rust does not expose the UseAfterScope option.
+      PipelineStartEPCallbacks.push_back([&](ModulePassManager &MPM) {
+        MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
+      });
+      OptimizerLastEPCallbacks.push_back(
+        [SanitizerOptions](FunctionPassManager &FPM, PassBuilder::OptimizationLevel Level) {
+          FPM.addPass(AddressSanitizerPass(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover));
+        }
+      );
+      PipelineStartEPCallbacks.push_back(
+        [SanitizerOptions](ModulePassManager &MPM) {
+          MPM.addPass(ModuleAddressSanitizerPass(
+              /*CompileKernel=*/false, SanitizerOptions->SanitizeRecover));
+        }
+      );
+    }
+  }
+
+  ModulePassManager MPM(DebugPassManager);
+  if (!NoPrepopulatePasses) {
+    if (OptLevel == PassBuilder::O0) {
+      for (const auto &C : PipelineStartEPCallbacks)
+        C(MPM);
+
+      if (!OptimizerLastEPCallbacks.empty()) {
+        FunctionPassManager FPM(DebugPassManager);
+        for (const auto &C : OptimizerLastEPCallbacks)
+          C(FPM, OptLevel);
+        MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
+      }
+
+      MPM.addPass(AlwaysInlinerPass(/*InsertLifetimeIntrinsics=*/false));
+
+#if LLVM_VERSION_GE(10, 0)
+      if (PGOOpt) {
+        PB.addPGOInstrPassesForO0(
+            MPM, DebugPassManager, PGOOpt->Action == PGOOptions::IRInstr,
+            /*IsCS=*/false, PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile);
+      }
+#endif
+    } else {
+      for (const auto &C : PipelineStartEPCallbacks)
+        PB.registerPipelineStartEPCallback(C);
+      for (const auto &C : OptimizerLastEPCallbacks)
+        PB.registerOptimizerLastEPCallback(C);
+
+      switch (OptStage) {
+      case LLVMRustOptStage::PreLinkNoLTO:
+        MPM = PB.buildPerModuleDefaultPipeline(OptLevel, DebugPassManager);
+        break;
+      case LLVMRustOptStage::PreLinkThinLTO:
+        MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
+        break;
+      case LLVMRustOptStage::PreLinkFatLTO:
+        MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
+        break;
+      case LLVMRustOptStage::ThinLTO:
+        // FIXME: Does it make sense to pass the ModuleSummaryIndex?
+        // It only seems to be needed for C++ specific optimizations.
+        MPM = PB.buildThinLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
+        break;
+      case LLVMRustOptStage::FatLTO:
+        MPM = PB.buildLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
+        break;
+      }
+    }
+  }
+
+  if (UseThinLTOBuffers) {
+    MPM.addPass(CanonicalizeAliasesPass());
+    MPM.addPass(NameAnonGlobalPass());
+  }
+
+  // Upgrade all calls to old intrinsics first.
+  for (Module::iterator I = TheModule->begin(), E = TheModule->end(); I != E;)
+    UpgradeCallsToIntrinsic(&*I++); // must be post-increment, as we remove
+
+  MPM.run(*TheModule, MAM);
+#else
+  // The new pass manager has been available for a long time,
+  // but we don't bother supporting it on old LLVM versions.
+  report_fatal_error("New pass manager only supported since LLVM 9");
+#endif
+}
 
 // Callback to demangle function name
 // Parameters:
diff --git a/src/test/codegen/sanitizer-memory-track-orgins.rs b/src/test/codegen/sanitizer-memory-track-orgins.rs
index 1fd496b35dfcc..8ea41c5d44bb1 100644
--- a/src/test/codegen/sanitizer-memory-track-orgins.rs
+++ b/src/test/codegen/sanitizer-memory-track-orgins.rs
@@ -15,10 +15,10 @@
 #![crate_type="lib"]
 
 // MSAN-0-NOT: @__msan_track_origins
-// MSAN-1:     @__msan_track_origins = weak_odr local_unnamed_addr constant i32 1
-// MSAN-2:     @__msan_track_origins = weak_odr local_unnamed_addr constant i32 2
-// MSAN-1-LTO: @__msan_track_origins = weak_odr local_unnamed_addr constant i32 1
-// MSAN-2-LTO: @__msan_track_origins = weak_odr local_unnamed_addr constant i32 2
+// MSAN-1:     @__msan_track_origins = weak_odr {{.*}}constant i32 1
+// MSAN-2:     @__msan_track_origins = weak_odr {{.*}}constant i32 2
+// MSAN-1-LTO: @__msan_track_origins = weak_odr {{.*}}constant i32 1
+// MSAN-2-LTO: @__msan_track_origins = weak_odr {{.*}}constant i32 2
 //
 // MSAN-0-LABEL: define void @copy(
 // MSAN-1-LABEL: define void @copy(

From c8e567ddc82bed8aac617741b799d24184358fcd Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Wed, 12 Feb 2020 14:39:22 +0100
Subject: [PATCH 33/34] Minify CSS rules to be able to handle minified theme
 files as well

---
 src/librustdoc/theme.rs | 31 +++++++++++++++++--------------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs
index af1c50acb0a35..eb8eabe1c03eb 100644
--- a/src/librustdoc/theme.rs
+++ b/src/librustdoc/theme.rs
@@ -179,20 +179,23 @@ fn get_previous_positions(events: &[Events], mut pos: usize) -> Vec<usize> {
 }
 
 fn build_rule(v: &[u8], positions: &[usize]) -> String {
-    positions
-        .chunks(2)
-        .map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or(""))
-        .collect::<String>()
-        .trim()
-        .replace("\n", " ")
-        .replace("/", "")
-        .replace("\t", " ")
-        .replace("{", "")
-        .replace("}", "")
-        .split(' ')
-        .filter(|s| s.len() > 0)
-        .collect::<Vec<&str>>()
-        .join(" ")
+    minifier::css::minify(
+        &positions
+            .chunks(2)
+            .map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or(""))
+            .collect::<String>()
+            .trim()
+            .replace("\n", " ")
+            .replace("/", "")
+            .replace("\t", " ")
+            .replace("{", "")
+            .replace("}", "")
+            .split(' ')
+            .filter(|s| s.len() > 0)
+            .collect::<Vec<&str>>()
+            .join(" "),
+    )
+    .unwrap_or_else(|_| String::new())
 }
 
 fn inner(v: &[u8], events: &[Events], pos: &mut usize) -> FxHashSet<CssPath> {

From 109260f8f0d97d6f1aacefdee806103eac5144eb Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume1.gomez@gmail.com>
Date: Wed, 12 Feb 2020 14:39:40 +0100
Subject: [PATCH 34/34] Add test to check if minified theme are handled
 correctly

---
 src/librustdoc/theme/tests.rs | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/librustdoc/theme/tests.rs b/src/librustdoc/theme/tests.rs
index 9ead1d28007c1..b924215733d55 100644
--- a/src/librustdoc/theme/tests.rs
+++ b/src/librustdoc/theme/tests.rs
@@ -102,3 +102,16 @@ fn check_invalid_css() {
     let events = load_css_events(b"*");
     assert_eq!(events.len(), 0);
 }
+
+#[test]
+fn test_with_minification() {
+    let text = include_str!("../html/static/themes/dark.css");
+    let minified = minifier::css::minify(&text).expect("CSS minification failed");
+
+    let against = load_css_paths(text.as_bytes());
+    let other = load_css_paths(minified.as_bytes());
+
+    let mut ret = Vec::new();
+    get_differences(&against, &other, &mut ret);
+    assert!(ret.is_empty());
+}