diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 0eac04df3c9f5..a6df41f47ce55 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -16,6 +16,7 @@ use rustc_ast_pretty::pprust;
 use rustc_errors::{Applicability, DiagnosticBuilder, PResult};
 use rustc_span::source_map::{self, Span, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
+use rustc_span::{BytePos, Pos};
 use std::mem;
 use tracing::debug;
 
@@ -839,9 +840,10 @@ impl<'a> Parser<'a> {
         }
         use FloatComponent::*;
 
+        let float_str = float.as_str();
         let mut components = Vec::new();
         let mut ident_like = String::new();
-        for c in float.as_str().chars() {
+        for c in float_str.chars() {
             if c == '_' || c.is_ascii_alphanumeric() {
                 ident_like.push(c);
             } else if matches!(c, '.' | '+' | '-') {
@@ -857,8 +859,13 @@ impl<'a> Parser<'a> {
             components.push(IdentLike(ident_like));
         }
 
-        // FIXME: Make the span more precise.
+        // With proc macros the span can refer to anything, the source may be too short,
+        // or too long, or non-ASCII. It only makes sense to break our span into components
+        // if its underlying text is identical to our float literal.
         let span = self.token.span;
+        let can_take_span_apart =
+            || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref();
+
         match &*components {
             // 1e2
             [IdentLike(i)] => {
@@ -866,21 +873,40 @@ impl<'a> Parser<'a> {
             }
             // 1.
             [IdentLike(i), Punct('.')] => {
+                let (ident_span, dot_span) = if can_take_span_apart() {
+                    let (span, ident_len) = (span.data(), BytePos::from_usize(i.len()));
+                    let ident_span = span.with_hi(span.lo + ident_len);
+                    let dot_span = span.with_lo(span.lo + ident_len);
+                    (ident_span, dot_span)
+                } else {
+                    (span, span)
+                };
                 assert!(suffix.is_none());
                 let symbol = Symbol::intern(&i);
-                self.token = Token::new(token::Ident(symbol, false), span);
-                let next_token = Token::new(token::Dot, span);
+                self.token = Token::new(token::Ident(symbol, false), ident_span);
+                let next_token = Token::new(token::Dot, dot_span);
                 self.parse_tuple_field_access_expr(lo, base, symbol, None, Some(next_token))
             }
             // 1.2 | 1.2e3
             [IdentLike(i1), Punct('.'), IdentLike(i2)] => {
+                let (ident1_span, dot_span, ident2_span) = if can_take_span_apart() {
+                    let (span, ident1_len) = (span.data(), BytePos::from_usize(i1.len()));
+                    let ident1_span = span.with_hi(span.lo + ident1_len);
+                    let dot_span = span
+                        .with_lo(span.lo + ident1_len)
+                        .with_hi(span.lo + ident1_len + BytePos(1));
+                    let ident2_span = self.token.span.with_lo(span.lo + ident1_len + BytePos(1));
+                    (ident1_span, dot_span, ident2_span)
+                } else {
+                    (span, span, span)
+                };
                 let symbol1 = Symbol::intern(&i1);
-                self.token = Token::new(token::Ident(symbol1, false), span);
-                let next_token1 = Token::new(token::Dot, span);
+                self.token = Token::new(token::Ident(symbol1, false), ident1_span);
+                let next_token1 = Token::new(token::Dot, dot_span);
                 let base1 =
                     self.parse_tuple_field_access_expr(lo, base, symbol1, None, Some(next_token1));
                 let symbol2 = Symbol::intern(&i2);
-                let next_token2 = Token::new(token::Ident(symbol2, false), span);
+                let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span);
                 self.bump_with(next_token2); // `.`
                 self.parse_tuple_field_access_expr(lo, base1, symbol2, suffix, None)
             }
diff --git a/src/test/ui/parser/float-field.stderr b/src/test/ui/parser/float-field.stderr
index 62202b999648d..7090efc5014b3 100644
--- a/src/test/ui/parser/float-field.stderr
+++ b/src/test/ui/parser/float-field.stderr
@@ -271,10 +271,10 @@ LL |     s.1e1;
    = note: available fields are: `0`, `1`
 
 error[E0609]: no field `1e1` on type `(u8, u8)`
-  --> $DIR/float-field.rs:9:7
+  --> $DIR/float-field.rs:9:9
    |
 LL |     s.1.1e1;
-   |       ^^^^^
+   |         ^^^
 
 error[E0609]: no field `0x1e1` on type `S`
   --> $DIR/float-field.rs:24:7
@@ -288,7 +288,7 @@ error[E0609]: no field `0x1` on type `S`
   --> $DIR/float-field.rs:25:7
    |
 LL |     s.0x1.;
-   |       ^^^^ unknown field
+   |       ^^^ unknown field
    |
    = note: available fields are: `0`, `1`
 
@@ -296,7 +296,7 @@ error[E0609]: no field `0x1` on type `S`
   --> $DIR/float-field.rs:28:7
    |
 LL |     s.0x1.1;
-   |       ^^^^^ unknown field
+   |       ^^^ unknown field
    |
    = note: available fields are: `0`, `1`
 
@@ -304,7 +304,7 @@ error[E0609]: no field `0x1` on type `S`
   --> $DIR/float-field.rs:30:7
    |
 LL |     s.0x1.1e1;
-   |       ^^^^^^^ unknown field
+   |       ^^^ unknown field
    |
    = note: available fields are: `0`, `1`
 
diff --git a/src/test/ui/tuple/index-invalid.stderr b/src/test/ui/tuple/index-invalid.stderr
index 800b5a31d98ab..8d22f458a6c6e 100644
--- a/src/test/ui/tuple/index-invalid.stderr
+++ b/src/test/ui/tuple/index-invalid.stderr
@@ -2,19 +2,19 @@ error[E0609]: no field `1` on type `(((),),)`
   --> $DIR/index-invalid.rs:2:22
    |
 LL |     let _ = (((),),).1.0;
-   |                      ^^^
+   |                      ^
 
 error[E0609]: no field `1` on type `((),)`
-  --> $DIR/index-invalid.rs:4:22
+  --> $DIR/index-invalid.rs:4:24
    |
 LL |     let _ = (((),),).0.1;
-   |                      ^^^
+   |                        ^
 
 error[E0609]: no field `000` on type `(((),),)`
   --> $DIR/index-invalid.rs:6:22
    |
 LL |     let _ = (((),),).000.000;
-   |                      ^^^^^^^
+   |                      ^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/union/union-deref.stderr b/src/test/ui/union/union-deref.stderr
index fb16649767fb7..f7722764cd3f0 100644
--- a/src/test/ui/union/union-deref.stderr
+++ b/src/test/ui/union/union-deref.stderr
@@ -29,7 +29,7 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field
   --> $DIR/union-deref.rs:23:14
    |
 LL |     unsafe { u.f.0.0 = Vec::new() };
-   |              ^^^^^^^
+   |              ^^^^^
    |
    = help: writing to this reference calls the destructor for the old value
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
@@ -38,7 +38,7 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field
   --> $DIR/union-deref.rs:25:19
    |
 LL |     unsafe { &mut u.f.0.0 };
-   |                   ^^^^^^^
+   |                   ^^^^^
    |
    = help: writing to this reference calls the destructor for the old value
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
@@ -47,7 +47,7 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field
   --> $DIR/union-deref.rs:27:14
    |
 LL |     unsafe { u.f.0.0.push(0) };
-   |              ^^^^^^^
+   |              ^^^^^
    |
    = help: writing to this reference calls the destructor for the old value
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor