about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-10-09 22:36:14 +0000
committerbors <bors@rust-lang.org>2018-10-09 22:36:14 +0000
commiteae47a40484a085f699c3175d51e74901c607e65 (patch)
treecc668188444c2ecdbc605b7855bc98ce9fcf960e
parent96cafc53cfc6667a03c8e77d8e0a2fc96555ff6b (diff)
parent1f7dafbb778dc9bff6a13828813fbcd105d977c9 (diff)
downloadrust-eae47a40484a085f699c3175d51e74901c607e65.tar.gz
rust-eae47a40484a085f699c3175d51e74901c607e65.zip
Auto merge of #54734 - pawroman:fix_range_borrowing_suggestion, r=varkor
Fix range literals borrowing suggestions

Fixes #54505. The compiler issued incorrect range borrowing suggestions (missing `()` around borrows of range literals). This was not correct syntax (see the issue for an example).

With changes in this PR, this is fixed for all types of `Range` literals.

Thanks again to @varkor and @estebank for their invaluable help and guidance.

r? @varkor
-rw-r--r--src/librustc_typeck/check/demand.rs75
-rw-r--r--src/test/ui/range/issue-54505-no-literals.fixed75
-rw-r--r--src/test/ui/range/issue-54505-no-literals.rs75
-rw-r--r--src/test/ui/range/issue-54505-no-literals.stderr147
-rw-r--r--src/test/ui/range/issue-54505-no-std.rs57
-rw-r--r--src/test/ui/range/issue-54505-no-std.stderr77
-rw-r--r--src/test/ui/range/issue-54505.fixed43
-rw-r--r--src/test/ui/range/issue-54505.rs43
-rw-r--r--src/test/ui/range/issue-54505.stderr75
9 files changed, 664 insertions, 3 deletions
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 71c78e7f87c..85b6bcbd144 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -309,11 +309,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 };
                 if self.can_coerce(ref_ty, expected) {
                     if let Ok(src) = cm.span_to_snippet(sp) {
-                        let sugg_expr = match expr.node { // parenthesize if needed (Issue #46756)
+                        let needs_parens = match expr.node {
+                            // parenthesize if needed (Issue #46756)
                             hir::ExprKind::Cast(_, _) |
-                            hir::ExprKind::Binary(_, _, _) => format!("({})", src),
-                            _ => src,
+                            hir::ExprKind::Binary(_, _, _) => true,
+                            // parenthesize borrows of range literals (Issue #54505)
+                            _ if self.is_range_literal(expr) => true,
+                            _ => false,
                         };
+                        let sugg_expr = if needs_parens {
+                            format!("({})", src)
+                        } else {
+                            src
+                        };
+
                         if let Some(sugg) = self.can_use_as_ref(expr) {
                             return Some(sugg);
                         }
@@ -374,6 +383,66 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         None
     }
 
+    /// This function checks if the specified expression is a built-in range literal.
+    /// (See: `LoweringContext::lower_expr()` in `src/librustc/hir/lowering.rs`).
+    fn is_range_literal(&self, expr: &hir::Expr) -> bool {
+        use hir::{Path, QPath, ExprKind, TyKind};
+
+        // We support `::std::ops::Range` and `::core::ops::Range` prefixes
+        let is_range_path = |path: &Path| {
+            let mut segs = path.segments.iter()
+                .map(|seg| seg.ident.as_str());
+
+            if let (Some(root), Some(std_core), Some(ops), Some(range), None) =
+                (segs.next(), segs.next(), segs.next(), segs.next(), segs.next())
+            {
+                // "{{root}}" is the equivalent of `::` prefix in Path
+                root == "{{root}}" && (std_core == "std" || std_core == "core")
+                    && ops == "ops" && range.starts_with("Range")
+            } else {
+                false
+            }
+        };
+
+        let span_is_range_literal = |span: &Span| {
+            // Check whether a span corresponding to a range expression
+            // is a range literal, rather than an explicit struct or `new()` call.
+            let source_map = self.tcx.sess.source_map();
+            let end_point = source_map.end_point(*span);
+
+            if let Ok(end_string) = source_map.span_to_snippet(end_point) {
+                !(end_string.ends_with("}") || end_string.ends_with(")"))
+            } else {
+                false
+            }
+        };
+
+        match expr.node {
+            // All built-in range literals but `..=` and `..` desugar to Structs
+            ExprKind::Struct(QPath::Resolved(None, ref path), _, _) |
+            // `..` desugars to its struct path
+            ExprKind::Path(QPath::Resolved(None, ref path)) => {
+                return is_range_path(&path) && span_is_range_literal(&expr.span);
+            }
+
+            // `..=` desugars into `::std::ops::RangeInclusive::new(...)`
+            ExprKind::Call(ref func, _) => {
+                if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node {
+                    if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node {
+                        let call_to_new = segment.ident.as_str() == "new";
+
+                        return is_range_path(&path) && span_is_range_literal(&expr.span)
+                            && call_to_new;
+                    }
+                }
+            }
+
+            _ => {}
+        }
+
+        false
+    }
+
     pub fn check_for_cast(&self,
                       err: &mut DiagnosticBuilder<'tcx>,
                       expr: &hir::Expr,
diff --git a/src/test/ui/range/issue-54505-no-literals.fixed b/src/test/ui/range/issue-54505-no-literals.fixed
new file mode 100644
index 00000000000..4d8f67182b9
--- /dev/null
+++ b/src/test/ui/range/issue-54505-no-literals.fixed
@@ -0,0 +1,75 @@
+// run-rustfix
+
+// Regression test for changes introduced while fixing #54505
+
+// This test uses non-literals for Ranges
+// (expecting no parens with borrow suggestion)
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+    take_range(&std::ops::Range { start: 0, end: 1 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::Range { start: 0, end: 1 }
+
+    take_range(&::std::ops::Range { start: 0, end: 1 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::Range { start: 0, end: 1 }
+
+    take_range(&std::ops::RangeFrom { start: 1 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::RangeFrom { start: 1 }
+
+    take_range(&::std::ops::RangeFrom { start: 1 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::RangeFrom { start: 1 }
+
+    take_range(&std::ops::RangeFull {});
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::RangeFull {}
+
+    take_range(&::std::ops::RangeFull {});
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::RangeFull {}
+
+    take_range(&std::ops::RangeInclusive::new(0, 1));
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::RangeInclusive::new(0, 1)
+
+    take_range(&::std::ops::RangeInclusive::new(0, 1));
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::RangeInclusive::new(0, 1)
+
+    take_range(&std::ops::RangeTo { end: 5 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::RangeTo { end: 5 }
+
+    take_range(&::std::ops::RangeTo { end: 5 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::RangeTo { end: 5 }
+
+    take_range(&std::ops::RangeToInclusive { end: 5 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::RangeToInclusive { end: 5 }
+
+    take_range(&::std::ops::RangeToInclusive { end: 5 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::RangeToInclusive { end: 5 }
+}
diff --git a/src/test/ui/range/issue-54505-no-literals.rs b/src/test/ui/range/issue-54505-no-literals.rs
new file mode 100644
index 00000000000..dc21dcbc2db
--- /dev/null
+++ b/src/test/ui/range/issue-54505-no-literals.rs
@@ -0,0 +1,75 @@
+// run-rustfix
+
+// Regression test for changes introduced while fixing #54505
+
+// This test uses non-literals for Ranges
+// (expecting no parens with borrow suggestion)
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+    take_range(std::ops::Range { start: 0, end: 1 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::Range { start: 0, end: 1 }
+
+    take_range(::std::ops::Range { start: 0, end: 1 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::Range { start: 0, end: 1 }
+
+    take_range(std::ops::RangeFrom { start: 1 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::RangeFrom { start: 1 }
+
+    take_range(::std::ops::RangeFrom { start: 1 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::RangeFrom { start: 1 }
+
+    take_range(std::ops::RangeFull {});
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::RangeFull {}
+
+    take_range(::std::ops::RangeFull {});
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::RangeFull {}
+
+    take_range(std::ops::RangeInclusive::new(0, 1));
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::RangeInclusive::new(0, 1)
+
+    take_range(::std::ops::RangeInclusive::new(0, 1));
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::RangeInclusive::new(0, 1)
+
+    take_range(std::ops::RangeTo { end: 5 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::RangeTo { end: 5 }
+
+    take_range(::std::ops::RangeTo { end: 5 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::RangeTo { end: 5 }
+
+    take_range(std::ops::RangeToInclusive { end: 5 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &std::ops::RangeToInclusive { end: 5 }
+
+    take_range(::std::ops::RangeToInclusive { end: 5 });
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &::std::ops::RangeToInclusive { end: 5 }
+}
diff --git a/src/test/ui/range/issue-54505-no-literals.stderr b/src/test/ui/range/issue-54505-no-literals.stderr
new file mode 100644
index 00000000000..b8811c98d21
--- /dev/null
+++ b/src/test/ui/range/issue-54505-no-literals.stderr
@@ -0,0 +1,147 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:16:16
+   |
+LL |     take_range(std::ops::Range { start: 0, end: 1 });
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::Range`
+   |                help: consider borrowing here: `&std::ops::Range { start: 0, end: 1 }`
+   |
+   = note: expected type `&_`
+              found type `std::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:21:16
+   |
+LL |     take_range(::std::ops::Range { start: 0, end: 1 });
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::Range`
+   |                help: consider borrowing here: `&::std::ops::Range { start: 0, end: 1 }`
+   |
+   = note: expected type `&_`
+              found type `std::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:26:16
+   |
+LL |     take_range(std::ops::RangeFrom { start: 1 });
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeFrom`
+   |                help: consider borrowing here: `&std::ops::RangeFrom { start: 1 }`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:31:16
+   |
+LL |     take_range(::std::ops::RangeFrom { start: 1 });
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeFrom`
+   |                help: consider borrowing here: `&::std::ops::RangeFrom { start: 1 }`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:36:16
+   |
+LL |     take_range(std::ops::RangeFull {});
+   |                ^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeFull`
+   |                help: consider borrowing here: `&std::ops::RangeFull {}`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeFull`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:41:16
+   |
+LL |     take_range(::std::ops::RangeFull {});
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeFull`
+   |                help: consider borrowing here: `&::std::ops::RangeFull {}`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeFull`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:46:16
+   |
+LL |     take_range(std::ops::RangeInclusive::new(0, 1));
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeInclusive`
+   |                help: consider borrowing here: `&std::ops::RangeInclusive::new(0, 1)`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:51:16
+   |
+LL |     take_range(::std::ops::RangeInclusive::new(0, 1));
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeInclusive`
+   |                help: consider borrowing here: `&::std::ops::RangeInclusive::new(0, 1)`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:56:16
+   |
+LL |     take_range(std::ops::RangeTo { end: 5 });
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeTo`
+   |                help: consider borrowing here: `&std::ops::RangeTo { end: 5 }`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:61:16
+   |
+LL |     take_range(::std::ops::RangeTo { end: 5 });
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeTo`
+   |                help: consider borrowing here: `&::std::ops::RangeTo { end: 5 }`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:66:16
+   |
+LL |     take_range(std::ops::RangeToInclusive { end: 5 });
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeToInclusive`
+   |                help: consider borrowing here: `&std::ops::RangeToInclusive { end: 5 }`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeToInclusive<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-literals.rs:71:16
+   |
+LL |     take_range(::std::ops::RangeToInclusive { end: 5 });
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeToInclusive`
+   |                help: consider borrowing here: `&::std::ops::RangeToInclusive { end: 5 }`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeToInclusive<{integer}>`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/range/issue-54505-no-std.rs b/src/test/ui/range/issue-54505-no-std.rs
new file mode 100644
index 00000000000..1915fd82899
--- /dev/null
+++ b/src/test/ui/range/issue-54505-no-std.rs
@@ -0,0 +1,57 @@
+// error-pattern: `#[panic_handler]` function required, but not found
+
+// Regression test for #54505 - range borrowing suggestion had
+// incorrect syntax (missing parentheses).
+
+// This test doesn't use std
+// (so all Ranges resolve to core::ops::Range...)
+
+#![no_std]
+#![feature(lang_items)]
+
+use core::ops::RangeBounds;
+
+#[cfg(not(target_arch = "wasm32"))]
+#[lang = "eh_personality"]
+extern fn eh_personality() {}
+
+#[cfg(target_os = "windows")]
+#[lang = "eh_unwind_resume"]
+extern fn eh_unwind_resume() {}
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+    take_range(0..1);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(0..1)
+
+    take_range(1..);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(1..)
+
+    take_range(..);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(..)
+
+    take_range(0..=1);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(0..=1)
+
+    take_range(..5);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(..5)
+
+    take_range(..=42);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(..=42)
+}
diff --git a/src/test/ui/range/issue-54505-no-std.stderr b/src/test/ui/range/issue-54505-no-std.stderr
new file mode 100644
index 00000000000..4922e59953c
--- /dev/null
+++ b/src/test/ui/range/issue-54505-no-std.stderr
@@ -0,0 +1,77 @@
+error: `#[panic_handler]` function required, but not found
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-std.rs:28:16
+   |
+LL |     take_range(0..1);
+   |                ^^^^
+   |                |
+   |                expected reference, found struct `core::ops::Range`
+   |                help: consider borrowing here: `&(0..1)`
+   |
+   = note: expected type `&_`
+              found type `core::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-std.rs:33:16
+   |
+LL |     take_range(1..);
+   |                ^^^
+   |                |
+   |                expected reference, found struct `core::ops::RangeFrom`
+   |                help: consider borrowing here: `&(1..)`
+   |
+   = note: expected type `&_`
+              found type `core::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-std.rs:38:16
+   |
+LL |     take_range(..);
+   |                ^^
+   |                |
+   |                expected reference, found struct `core::ops::RangeFull`
+   |                help: consider borrowing here: `&(..)`
+   |
+   = note: expected type `&_`
+              found type `core::ops::RangeFull`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-std.rs:43:16
+   |
+LL |     take_range(0..=1);
+   |                ^^^^^
+   |                |
+   |                expected reference, found struct `core::ops::RangeInclusive`
+   |                help: consider borrowing here: `&(0..=1)`
+   |
+   = note: expected type `&_`
+              found type `core::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-std.rs:48:16
+   |
+LL |     take_range(..5);
+   |                ^^^
+   |                |
+   |                expected reference, found struct `core::ops::RangeTo`
+   |                help: consider borrowing here: `&(..5)`
+   |
+   = note: expected type `&_`
+              found type `core::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505-no-std.rs:53:16
+   |
+LL |     take_range(..=42);
+   |                ^^^^^
+   |                |
+   |                expected reference, found struct `core::ops::RangeToInclusive`
+   |                help: consider borrowing here: `&(..=42)`
+   |
+   = note: expected type `&_`
+              found type `core::ops::RangeToInclusive<{integer}>`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/range/issue-54505.fixed b/src/test/ui/range/issue-54505.fixed
new file mode 100644
index 00000000000..f8298c0b5ce
--- /dev/null
+++ b/src/test/ui/range/issue-54505.fixed
@@ -0,0 +1,43 @@
+// run-rustfix
+
+// Regression test for #54505 - range borrowing suggestion had
+// incorrect syntax (missing parentheses).
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+    take_range(&(0..1));
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(0..1)
+
+    take_range(&(1..));
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(1..)
+
+    take_range(&(..));
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(..)
+
+    take_range(&(0..=1));
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(0..=1)
+
+    take_range(&(..5));
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(..5)
+
+    take_range(&(..=42));
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(..=42)
+}
diff --git a/src/test/ui/range/issue-54505.rs b/src/test/ui/range/issue-54505.rs
new file mode 100644
index 00000000000..03673252dd3
--- /dev/null
+++ b/src/test/ui/range/issue-54505.rs
@@ -0,0 +1,43 @@
+// run-rustfix
+
+// Regression test for #54505 - range borrowing suggestion had
+// incorrect syntax (missing parentheses).
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+    take_range(0..1);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(0..1)
+
+    take_range(1..);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(1..)
+
+    take_range(..);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(..)
+
+    take_range(0..=1);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(0..=1)
+
+    take_range(..5);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(..5)
+
+    take_range(..=42);
+    //~^ ERROR mismatched types [E0308]
+    //~| HELP consider borrowing here
+    //~| SUGGESTION &(..=42)
+}
diff --git a/src/test/ui/range/issue-54505.stderr b/src/test/ui/range/issue-54505.stderr
new file mode 100644
index 00000000000..d6e1fb0cef2
--- /dev/null
+++ b/src/test/ui/range/issue-54505.stderr
@@ -0,0 +1,75 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-54505.rs:14:16
+   |
+LL |     take_range(0..1);
+   |                ^^^^
+   |                |
+   |                expected reference, found struct `std::ops::Range`
+   |                help: consider borrowing here: `&(0..1)`
+   |
+   = note: expected type `&_`
+              found type `std::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505.rs:19:16
+   |
+LL |     take_range(1..);
+   |                ^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeFrom`
+   |                help: consider borrowing here: `&(1..)`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505.rs:24:16
+   |
+LL |     take_range(..);
+   |                ^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeFull`
+   |                help: consider borrowing here: `&(..)`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeFull`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505.rs:29:16
+   |
+LL |     take_range(0..=1);
+   |                ^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeInclusive`
+   |                help: consider borrowing here: `&(0..=1)`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505.rs:34:16
+   |
+LL |     take_range(..5);
+   |                ^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeTo`
+   |                help: consider borrowing here: `&(..5)`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+  --> $DIR/issue-54505.rs:39:16
+   |
+LL |     take_range(..=42);
+   |                ^^^^^
+   |                |
+   |                expected reference, found struct `std::ops::RangeToInclusive`
+   |                help: consider borrowing here: `&(..=42)`
+   |
+   = note: expected type `&_`
+              found type `std::ops::RangeToInclusive<{integer}>`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0308`.