diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 2344cd11f66..bcad3fbc841 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1239,8 +1239,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
           "print the result of the monomorphization collection pass"),
     mir_opt_level: usize = (1, parse_uint, [TRACKED],
           "set the MIR optimization level (0-3, default: 1)"),
-    mutable_noalias: bool = (false, parse_bool, [TRACKED],
-          "emit noalias metadata for mutable references"),
+    mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
+          "emit noalias metadata for mutable references (default: yes on LLVM >= 6)"),
     arg_align_attributes: bool = (false, parse_bool, [TRACKED],
           "emit align metadata for reference arguments"),
     dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index 5f186e7514e..21436b74731 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -10,6 +10,7 @@
 
 use abi::{FnType, FnTypeExt};
 use common::*;
+use llvm;
 use rustc::hir;
 use rustc::ty::{self, Ty, TypeFoldable};
 use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout};
@@ -428,8 +429,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
                         PointerKind::Shared
                     },
                     hir::MutMutable => {
-                        if cx.tcx.sess.opts.debugging_opts.mutable_noalias ||
-                           cx.tcx.sess.panic_strategy() == PanicStrategy::Abort {
+                        // Only emit noalias annotations for LLVM >= 6 or in panic=abort
+                        // mode, as prior versions had many bugs in conjunction with
+                        // unwinding. See also issue #31681.
+                        let mutable_noalias = cx.tcx.sess.opts.debugging_opts.mutable_noalias
+                            .unwrap_or(unsafe { llvm::LLVMRustVersionMajor() >= 6 }
+                                || cx.tcx.sess.panic_strategy() == PanicStrategy::Abort);
+                        if mutable_noalias {
                             PointerKind::UniqueBorrowed
                         } else {
                             PointerKind::Shared
diff --git a/src/test/codegen/function-arguments.rs b/src/test/codegen/function-arguments.rs
index 40a9ea5a181..e3fa7a7db39 100644
--- a/src/test/codegen/function-arguments.rs
+++ b/src/test/codegen/function-arguments.rs
@@ -10,6 +10,7 @@
 
 // compile-flags: -C no-prepopulate-passes
 // ignore-tidy-linelength
+// min-llvm-version 6.0
 
 #![crate_type = "lib"]
 #![feature(custom_attribute)]
@@ -52,16 +53,14 @@ pub fn named_borrow<'r>(_: &'r i32) {
 pub fn unsafe_borrow(_: &UnsafeInner) {
 }
 
-// CHECK: @mutable_unsafe_borrow(i16* dereferenceable(2) %arg0)
+// CHECK: @mutable_unsafe_borrow(i16* noalias dereferenceable(2) %arg0)
 // ... unless this is a mutable borrow, those never alias
-// ... except that there's this LLVM bug that forces us to not use noalias, see #29485
 #[no_mangle]
 pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
 }
 
-// CHECK: @mutable_borrow(i32* dereferenceable(4) %arg0)
+// CHECK: @mutable_borrow(i32* noalias dereferenceable(4) %arg0)
 // FIXME #25759 This should also have `nocapture`
-// ... there's this LLVM bug that forces us to not use noalias, see #29485
 #[no_mangle]
 pub fn mutable_borrow(_: &mut i32) {
 }
@@ -103,9 +102,8 @@ pub fn helper(_: usize) {
 pub fn slice(_: &[u8]) {
 }
 
-// CHECK: @mutable_slice([0 x i8]* nonnull %arg0.0, [[USIZE]] %arg0.1)
+// CHECK: @mutable_slice([0 x i8]* noalias nonnull %arg0.0, [[USIZE]] %arg0.1)
 // FIXME #25759 This should also have `nocapture`
-// ... there's this LLVM bug that forces us to not use noalias, see #29485
 #[no_mangle]
 pub fn mutable_slice(_: &mut [u8]) {
 }