about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarcel Hellwig <git@cookiesoft.de>2019-10-16 13:25:42 +0200
committerMarcel Hellwig <git@cookiesoft.de>2019-10-22 10:39:55 +0200
commit5572476a36f85959ec820d0886548a747ce0570a (patch)
tree386f26fa379a55ad235e95fe8aea8e8dfd5ab270
parent1d0f62570b2f58b09b991f7312dd1f1564c613f0 (diff)
downloadrust-5572476a36f85959ec820d0886548a747ce0570a.tar.gz
rust-5572476a36f85959ec820d0886548a747ce0570a.zip
Add lint for debug_assert_with_mut_call
This lint will complain when you put a mutable function/method call
inside a `debug_assert` macro, because it will not be executed in
release mode, therefore it will change the execution flow, which is not
wanted.
-rw-r--r--CHANGELOG.md1
-rw-r--r--README.md2
-rw-r--r--clippy_lints/src/lib.rs4
-rw-r--r--clippy_lints/src/mutable_debug_assertion.rs155
-rw-r--r--src/lintlist/mod.rs9
-rw-r--r--tests/ui/debug_assert_with_mut_call.rs124
-rw-r--r--tests/ui/debug_assert_with_mut_call.stderr172
7 files changed, 465 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ef21695cbab..7b32914854f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -966,6 +966,7 @@ Released 2018-09-13
 [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
 [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute
 [`dbg_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro
+[`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
 [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
 [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
 [`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
diff --git a/README.md b/README.md
index 41b8b4199ec..87ef441eadd 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-[There are 331 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are 332 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you:
 
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index bff1952cce7..8f0b3c21682 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -230,6 +230,7 @@ pub mod mul_add;
 pub mod multiple_crate_versions;
 pub mod mut_mut;
 pub mod mut_reference;
+pub mod mutable_debug_assertion;
 pub mod mutex_atomic;
 pub mod needless_bool;
 pub mod needless_borrow;
@@ -610,6 +611,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
     reg.register_late_lint_pass(box comparison_chain::ComparisonChain);
     reg.register_late_lint_pass(box mul_add::MulAddCheck);
     reg.register_late_lint_pass(box unused_self::UnusedSelf);
+    reg.register_late_lint_pass(box mutable_debug_assertion::DebugAssertWithMutCall);
 
     reg.register_lint_group("clippy::restriction", Some("clippy_restriction"), vec![
         arithmetic::FLOAT_ARITHMETIC,
@@ -855,6 +857,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
         misc_early::ZERO_PREFIXED_LITERAL,
         mul_add::MANUAL_MUL_ADD,
         mut_reference::UNNECESSARY_MUT_PASSED,
+        mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
         mutex_atomic::MUTEX_ATOMIC,
         needless_bool::BOOL_COMPARISON,
         needless_bool::NEEDLESS_BOOL,
@@ -1160,6 +1163,7 @@ pub fn register_plugins(reg: &mut rustc_driver::plugin::Registry<'_>, conf: &Con
         misc::CMP_NAN,
         misc::FLOAT_CMP,
         misc::MODULO_ONE,
+        mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL,
         non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
         non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
         open_options::NONSENSICAL_OPEN_OPTIONS,
diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs
new file mode 100644
index 00000000000..1184db0587b
--- /dev/null
+++ b/clippy_lints/src/mutable_debug_assertion.rs
@@ -0,0 +1,155 @@
+use crate::utils::{is_direct_expn_of, span_lint};
+use if_chain::if_chain;
+use matches::matches;
+use rustc::hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc::hir::{Expr, ExprKind, Mutability, StmtKind, UnOp};
+use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
+use rustc::{declare_lint_pass, declare_tool_lint, ty};
+use syntax_pos::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for function/method calls with a mutable
+    /// parameter in `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!` macros.
+    ///
+    /// **Why is this bad?** In release builds `debug_assert!` macros are optimized out by the
+    /// compiler.
+    /// Therefore mutating something in a `debug_assert!` macro results in different behaviour
+    /// between a release and debug build.
+    ///
+    /// **Known problems:** None
+    ///
+    /// **Example:**
+    /// ```rust,ignore
+    /// debug_assert_eq!(vec![3].pop(), Some(3));
+    /// // or
+    /// fn take_a_mut_parameter(_: &mut u32) -> bool { unimplemented!() }
+    /// debug_assert!(take_a_mut_parameter(&mut 5));
+    /// ```
+    pub DEBUG_ASSERT_WITH_MUT_CALL,
+    correctness,
+    "mutable arguments in `debug_assert{,_ne,_eq}!`"
+}
+
+declare_lint_pass!(DebugAssertWithMutCall => [DEBUG_ASSERT_WITH_MUT_CALL]);
+
+const DEBUG_MACRO_NAMES: [&str; 3] = ["debug_assert", "debug_assert_eq", "debug_assert_ne"];
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for DebugAssertWithMutCall {
+    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
+        for dmn in &DEBUG_MACRO_NAMES {
+            if is_direct_expn_of(e.span, dmn).is_some() {
+                if let Some(span) = extract_call(cx, e) {
+                    span_lint(
+                        cx,
+                        DEBUG_ASSERT_WITH_MUT_CALL,
+                        span,
+                        &format!("do not call a function with mutable arguments inside of `{}!`", dmn),
+                    );
+                }
+            }
+        }
+    }
+}
+
+//HACK(hellow554): remove this when #4694 is implemented
+#[allow(clippy::cognitive_complexity)]
+fn extract_call<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, e: &'tcx Expr) -> Option<Span> {
+    if_chain! {
+        if let ExprKind::Block(ref block, _) = e.kind;
+        if block.stmts.len() == 1;
+        if let StmtKind::Semi(ref matchexpr) = block.stmts[0].kind;
+        then {
+            if_chain! {
+                if let ExprKind::Match(ref ifclause, _, _) = matchexpr.kind;
+                if let ExprKind::DropTemps(ref droptmp) = ifclause.kind;
+                if let ExprKind::Unary(UnOp::UnNot, ref condition) = droptmp.kind;
+                then {
+                    // debug_assert
+                    let mut visitor = MutArgVisitor::new(cx);
+                    visitor.visit_expr(condition);
+                    return visitor.expr_span();
+                } else {
+                    // debug_assert_{eq,ne}
+                    if_chain! {
+                        if let ExprKind::Block(ref matchblock, _) = matchexpr.kind;
+                        if let Some(ref matchheader) = matchblock.expr;
+                        if let ExprKind::Match(ref headerexpr, _, _) = matchheader.kind;
+                        if let ExprKind::Tup(ref conditions) = headerexpr.kind;
+                        if conditions.len() == 2;
+                        then {
+                            if let ExprKind::AddrOf(_, ref lhs) = conditions[0].kind {
+                                let mut visitor = MutArgVisitor::new(cx);
+                                visitor.visit_expr(lhs);
+                                if let Some(span) = visitor.expr_span() {
+                                    return Some(span);
+                                }
+                            }
+                            if let ExprKind::AddrOf(_, ref rhs) = conditions[1].kind {
+                                let mut visitor = MutArgVisitor::new(cx);
+                                visitor.visit_expr(rhs);
+                                if let Some(span) = visitor.expr_span() {
+                                    return Some(span);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    None
+}
+
+struct MutArgVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'a, 'tcx>,
+    expr_span: Option<Span>,
+    found: bool,
+}
+
+impl<'a, 'tcx> MutArgVisitor<'a, 'tcx> {
+    fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
+        Self {
+            cx,
+            expr_span: None,
+            found: false,
+        }
+    }
+
+    fn expr_span(&self) -> Option<Span> {
+        if self.found {
+            self.expr_span
+        } else {
+            None
+        }
+    }
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
+    fn visit_expr(&mut self, expr: &'tcx Expr) {
+        match expr.kind {
+            ExprKind::AddrOf(Mutability::MutMutable, _) => {
+                self.found = true;
+                return;
+            },
+            ExprKind::Path(_) => {
+                if let Some(adj) = self.cx.tables.adjustments().get(expr.hir_id) {
+                    if adj
+                        .iter()
+                        .any(|a| matches!(a.target.kind, ty::Ref(_, _, Mutability::MutMutable)))
+                    {
+                        self.found = true;
+                        return;
+                    }
+                }
+            },
+            _ if !self.found => self.expr_span = Some(expr.span),
+            _ => return,
+        }
+        walk_expr(self, expr)
+    }
+
+    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+        NestedVisitorMap::OnlyBodies(&self.cx.tcx.hir())
+    }
+}
diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs
index f44ef226847..48ca368f5a9 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -6,7 +6,7 @@ pub use lint::Lint;
 pub use lint::LINT_LEVELS;
 
 // begin lint list, do not remove this comment, it’s used in `update_lints`
-pub const ALL_LINTS: [Lint; 331] = [
+pub const ALL_LINTS: [Lint; 332] = [
     Lint {
         name: "absurd_extreme_comparisons",
         group: "correctness",
@@ -281,6 +281,13 @@ pub const ALL_LINTS: [Lint; 331] = [
         module: "dbg_macro",
     },
     Lint {
+        name: "debug_assert_with_mut_call",
+        group: "correctness",
+        desc: "mutable arguments in `debug_assert{,_ne,_eq}!`",
+        deprecation: None,
+        module: "mutable_debug_assertion",
+    },
+    Lint {
         name: "decimal_literal_representation",
         group: "restriction",
         desc: "using decimal representation when hexadecimal would be better",
diff --git a/tests/ui/debug_assert_with_mut_call.rs b/tests/ui/debug_assert_with_mut_call.rs
new file mode 100644
index 00000000000..a588547b943
--- /dev/null
+++ b/tests/ui/debug_assert_with_mut_call.rs
@@ -0,0 +1,124 @@
+#![feature(custom_inner_attributes)]
+#![rustfmt::skip]
+#![allow(clippy::trivially_copy_pass_by_ref, clippy::cognitive_complexity, clippy::redundant_closure_call)]
+
+struct S;
+
+impl S {
+    fn bool_self_ref(&self) -> bool { false }
+    fn bool_self_mut(&mut self) -> bool { false }
+    fn bool_self_ref_arg_ref(&self, _: &u32) -> bool { false }
+    fn bool_self_ref_arg_mut(&self, _: &mut u32) -> bool { false }
+    fn bool_self_mut_arg_ref(&mut self, _: &u32) -> bool { false }
+    fn bool_self_mut_arg_mut(&mut self, _: &mut u32) -> bool { false }
+
+    fn u32_self_ref(&self) -> u32 { 0 }
+    fn u32_self_mut(&mut self) -> u32 { 0 }
+    fn u32_self_ref_arg_ref(&self, _: &u32) -> u32 { 0 }
+    fn u32_self_ref_arg_mut(&self, _: &mut u32) -> u32 { 0 }
+    fn u32_self_mut_arg_ref(&mut self, _: &u32) -> u32 { 0 }
+    fn u32_self_mut_arg_mut(&mut self, _: &mut u32) -> u32 { 0 }
+}
+
+fn bool_ref(_: &u32) -> bool { false }
+fn bool_mut(_: &mut u32) -> bool { false }
+fn u32_ref(_: &u32) -> u32 { 0 }
+fn u32_mut(_: &mut u32) -> u32 { 0 }
+
+fn func_non_mutable() {
+    debug_assert!(bool_ref(&3));
+    debug_assert!(!bool_ref(&3));
+
+    debug_assert_eq!(0, u32_ref(&3));
+    debug_assert_eq!(u32_ref(&3), 0);
+
+    debug_assert_ne!(1, u32_ref(&3));
+    debug_assert_ne!(u32_ref(&3), 1);
+}
+
+fn func_mutable() {
+    debug_assert!(bool_mut(&mut 3));
+    debug_assert!(!bool_mut(&mut 3));
+
+    debug_assert_eq!(0, u32_mut(&mut 3));
+    debug_assert_eq!(u32_mut(&mut 3), 0);
+
+    debug_assert_ne!(1, u32_mut(&mut 3));
+    debug_assert_ne!(u32_mut(&mut 3), 1);
+}
+
+fn method_non_mutable() {
+    debug_assert!(S.bool_self_ref());
+    debug_assert!(S.bool_self_ref_arg_ref(&3));
+
+    debug_assert_eq!(S.u32_self_ref(), 0);
+    debug_assert_eq!(S.u32_self_ref_arg_ref(&3), 0);
+
+    debug_assert_ne!(S.u32_self_ref(), 1);
+    debug_assert_ne!(S.u32_self_ref_arg_ref(&3), 1);
+}
+
+fn method_mutable() {
+    debug_assert!(S.bool_self_mut());
+    debug_assert!(!S.bool_self_mut());
+    debug_assert!(S.bool_self_ref_arg_mut(&mut 3));
+    debug_assert!(S.bool_self_mut_arg_ref(&3));
+    debug_assert!(S.bool_self_mut_arg_mut(&mut 3));
+
+    debug_assert_eq!(S.u32_self_mut(), 0);
+    debug_assert_eq!(S.u32_self_mut_arg_ref(&3), 0);
+    debug_assert_eq!(S.u32_self_ref_arg_mut(&mut 3), 0);
+    debug_assert_eq!(S.u32_self_mut_arg_mut(&mut 3), 0);
+
+    debug_assert_ne!(S.u32_self_mut(), 1);
+    debug_assert_ne!(S.u32_self_mut_arg_ref(&3), 1);
+    debug_assert_ne!(S.u32_self_ref_arg_mut(&mut 3), 1);
+    debug_assert_ne!(S.u32_self_mut_arg_mut(&mut 3), 1);
+}
+
+fn misc() {
+    // with variable
+    let mut v: Vec<u32> = vec![1, 2, 3, 4];
+    debug_assert_eq!(v.get(0), Some(&1));
+    debug_assert_ne!(v[0], 2);
+    debug_assert_eq!(v.pop(), Some(1));
+    debug_assert_ne!(Some(3), v.pop());
+
+    let a = &mut 3;
+    debug_assert!(bool_mut(a));
+
+    // nested
+    debug_assert!(!(bool_ref(&u32_mut(&mut 3))));
+
+    // chained
+    debug_assert_eq!(v.pop().unwrap(), 3);
+
+    // format args
+    debug_assert!(bool_ref(&3), "w/o format");
+    debug_assert!(bool_mut(&mut 3), "w/o format");
+    debug_assert!(bool_ref(&3), "{} format", "w/");
+    debug_assert!(bool_mut(&mut 3), "{} format", "w/");
+
+    // sub block
+    let mut x = 42_u32;
+    debug_assert!({
+        bool_mut(&mut x);
+        x > 10
+    });
+
+    // closures
+    debug_assert!((|| {
+        let mut x = 42;
+        bool_mut(&mut x);
+        x > 10
+    })());
+}
+
+fn main() {
+    func_non_mutable();
+    func_mutable();
+    method_non_mutable();
+    method_mutable();
+
+    misc();
+}
diff --git a/tests/ui/debug_assert_with_mut_call.stderr b/tests/ui/debug_assert_with_mut_call.stderr
new file mode 100644
index 00000000000..48c7f4ea85e
--- /dev/null
+++ b/tests/ui/debug_assert_with_mut_call.stderr
@@ -0,0 +1,172 @@
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:40:19
+   |
+LL |     debug_assert!(bool_mut(&mut 3));
+   |                   ^^^^^^^^^^^^^^^^
+   |
+   = note: `#[deny(clippy::debug_assert_with_mut_call)]` on by default
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:41:20
+   |
+LL |     debug_assert!(!bool_mut(&mut 3));
+   |                    ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:43:25
+   |
+LL |     debug_assert_eq!(0, u32_mut(&mut 3));
+   |                         ^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:44:22
+   |
+LL |     debug_assert_eq!(u32_mut(&mut 3), 0);
+   |                      ^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:46:25
+   |
+LL |     debug_assert_ne!(1, u32_mut(&mut 3));
+   |                         ^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:47:22
+   |
+LL |     debug_assert_ne!(u32_mut(&mut 3), 1);
+   |                      ^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:62:19
+   |
+LL |     debug_assert!(S.bool_self_mut());
+   |                   ^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:63:20
+   |
+LL |     debug_assert!(!S.bool_self_mut());
+   |                    ^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:64:19
+   |
+LL |     debug_assert!(S.bool_self_ref_arg_mut(&mut 3));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:65:19
+   |
+LL |     debug_assert!(S.bool_self_mut_arg_ref(&3));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:66:19
+   |
+LL |     debug_assert!(S.bool_self_mut_arg_mut(&mut 3));
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:68:22
+   |
+LL |     debug_assert_eq!(S.u32_self_mut(), 0);
+   |                      ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:69:22
+   |
+LL |     debug_assert_eq!(S.u32_self_mut_arg_ref(&3), 0);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:70:22
+   |
+LL |     debug_assert_eq!(S.u32_self_ref_arg_mut(&mut 3), 0);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:71:22
+   |
+LL |     debug_assert_eq!(S.u32_self_mut_arg_mut(&mut 3), 0);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:73:22
+   |
+LL |     debug_assert_ne!(S.u32_self_mut(), 1);
+   |                      ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:74:22
+   |
+LL |     debug_assert_ne!(S.u32_self_mut_arg_ref(&3), 1);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:75:22
+   |
+LL |     debug_assert_ne!(S.u32_self_ref_arg_mut(&mut 3), 1);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:76:22
+   |
+LL |     debug_assert_ne!(S.u32_self_mut_arg_mut(&mut 3), 1);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:84:22
+   |
+LL |     debug_assert_eq!(v.pop(), Some(1));
+   |                      ^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_ne!`
+  --> $DIR/debug_assert_with_mut_call.rs:85:31
+   |
+LL |     debug_assert_ne!(Some(3), v.pop());
+   |                               ^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:88:19
+   |
+LL |     debug_assert!(bool_mut(a));
+   |                   ^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:91:31
+   |
+LL |     debug_assert!(!(bool_ref(&u32_mut(&mut 3))));
+   |                               ^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert_eq!`
+  --> $DIR/debug_assert_with_mut_call.rs:94:22
+   |
+LL |     debug_assert_eq!(v.pop().unwrap(), 3);
+   |                      ^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:98:19
+   |
+LL |     debug_assert!(bool_mut(&mut 3), "w/o format");
+   |                   ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:100:19
+   |
+LL |     debug_assert!(bool_mut(&mut 3), "{} format", "w/");
+   |                   ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:105:9
+   |
+LL |         bool_mut(&mut x);
+   |         ^^^^^^^^^^^^^^^^
+
+error: do not call a function with mutable arguments inside of `debug_assert!`
+  --> $DIR/debug_assert_with_mut_call.rs:112:9
+   |
+LL |         bool_mut(&mut x);
+   |         ^^^^^^^^^^^^^^^^
+
+error: aborting due to 28 previous errors
+