From c9fe0938767c8803330367806db8ba1ce81c7843 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Mon, 20 Sep 2021 15:39:16 +0000
Subject: [PATCH] Avoid the overflow with rustc+debugassertions in issue-44406

---
 compiler/rustc_span/src/lib.rs        | 29 +++++++++++++++++++++------
 src/test/ui/parser/issue-44406.stderr |  2 +-
 2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index ae685ffe974..21cfa78a6e4 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -785,13 +785,30 @@ impl Span {
     ///     ^^^^^^^^^^^^^^^^^
     /// ```
     pub fn until(self, end: Span) -> Span {
-        let span = self.data();
-        let end = end.data();
+        // Most of this function's body is copied from `to`.
+        // We can't just do `self.to(end.shrink_to_lo())`,
+        // because to also does some magic where it uses min/max so
+        // it can handle overlapping spans. Some advanced mis-use of
+        // `until` with different ctxts makes this visible.
+        let span_data = self.data();
+        let end_data = end.data();
+        // FIXME(jseyfried): `self.ctxt` should always equal `end.ctxt` here (cf. issue #23480).
+        // Return the macro span on its own to avoid weird diagnostic output. It is preferable to
+        // have an incomplete span than a completely nonsensical one.
+        if span_data.ctxt != end_data.ctxt {
+            if span_data.ctxt == SyntaxContext::root() {
+                return end;
+            } else if end_data.ctxt == SyntaxContext::root() {
+                return self;
+            }
+            // Both spans fall within a macro.
+            // FIXME(estebank): check if it is the *same* macro.
+        }
         Span::new(
-            span.lo,
-            end.lo,
-            if end.ctxt == SyntaxContext::root() { end.ctxt } else { span.ctxt },
-            if span.parent == end.parent { span.parent } else { None },
+            span_data.lo,
+            end_data.lo,
+            if end_data.ctxt == SyntaxContext::root() { end_data.ctxt } else { span_data.ctxt },
+            if span_data.parent == end_data.parent { span_data.parent } else { None },
         )
     }
 
diff --git a/src/test/ui/parser/issue-44406.stderr b/src/test/ui/parser/issue-44406.stderr
index 862026408ef..a37a806a157 100644
--- a/src/test/ui/parser/issue-44406.stderr
+++ b/src/test/ui/parser/issue-44406.stderr
@@ -26,7 +26,7 @@ LL |         bar {  }
 help: if `bar` is a function, use the arguments directly
    |
 LL -         bar(baz: $rest)
-LL +         bar(true);
+LL +         bar(: $rest)
    | 
 
 error: aborting due to 2 previous errors