From 31d72c2658e3ca3c51bb08ff5152c815d595e7ac Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Date: Sat, 7 Nov 2020 16:09:40 +0300
Subject: [PATCH] Accept arbitrary expressions in key-value attributes at parse
 time

---
 compiler/rustc_ast/src/ast.rs                 |  17 +--
 compiler/rustc_ast/src/mut_visit.rs           |  21 ++--
 compiler/rustc_ast/src/visit.rs               |   1 -
 compiler/rustc_ast_passes/src/feature_gate.rs |   4 +
 compiler/rustc_feature/src/active.rs          |   3 +
 compiler/rustc_parse/src/parser/mod.rs        |  27 ++--
 compiler/rustc_span/src/symbol.rs             |   1 +
 src/test/rustdoc/external-doc.rs              |  16 +++
 .../ast-json/ast-json-noexpand-output.stdout  |   2 +-
 src/test/ui/ast-json/ast-json-output.stdout   |   2 +-
 src/test/ui/attr-eq-token-tree.rs             |   2 +-
 src/test/ui/attr-eq-token-tree.stderr         |   6 +-
 src/test/ui/attributes/key-value-expansion.rs |  10 +-
 .../ui/attributes/key-value-expansion.stderr  |  21 ++--
 ...ture-gate-extended_key_value_attributes.rs |   8 ++
 ...-gate-extended_key_value_attributes.stderr |  39 ++++++
 src/test/ui/macros/macro-attribute.rs         |   2 +-
 src/test/ui/macros/macro-attribute.stderr     |   4 +-
 .../ui/malformed/malformed-interpolated.rs    |   7 +-
 .../malformed/malformed-interpolated.stderr   |  24 ++--
 src/test/ui/parser/attr-bad-meta-2.rs         |   2 +-
 src/test/ui/parser/attr-bad-meta-2.stderr     |   4 +-
 src/test/ui/suffixed-literal-meta.rs          |  14 +--
 src/test/ui/suffixed-literal-meta.stderr      | 118 ++----------------
 24 files changed, 145 insertions(+), 210 deletions(-)
 create mode 100644 src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs
 create mode 100644 src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr

diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 9d6ee65049a..220bbed7e78 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -24,7 +24,7 @@ pub use UnsafeSource::*;
 
 use crate::ptr::P;
 use crate::token::{self, CommentKind, DelimToken};
-use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree};
+use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -39,7 +39,6 @@ use rustc_span::{Span, DUMMY_SP};
 use std::cmp::Ordering;
 use std::convert::TryFrom;
 use std::fmt;
-use std::iter;
 
 #[cfg(test)]
 mod tests;
@@ -1514,20 +1513,6 @@ impl MacArgs {
         }
     }
 
-    /// Tokens together with the delimiters or `=`.
-    /// Use of this method generally means that something suboptimal or hacky is happening.
-    pub fn outer_tokens(&self) -> TokenStream {
-        match *self {
-            MacArgs::Empty => TokenStream::default(),
-            MacArgs::Delimited(dspan, delim, ref tokens) => {
-                TokenTree::Delimited(dspan, delim.to_token(), tokens.clone()).into()
-            }
-            MacArgs::Eq(eq_span, ref tokens) => {
-                iter::once(TokenTree::token(token::Eq, eq_span)).chain(tokens.trees()).collect()
-            }
-        }
-    }
-
     /// Whether a macro with these arguments needs a semicolon
     /// when used as a standalone item or statement.
     pub fn need_semicolon(&self) -> bool {
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index c4e92a9f6d1..3889ede7f4c 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -371,20 +371,15 @@ pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) {
             // The value in `#[key = VALUE]` must be visited as an expression for backward
             // compatibility, so that macros can be expanded in that position.
             if !vis.token_visiting_enabled() {
-                if let Some(TokenTree::Token(token)) = tokens.trees_ref().next() {
-                    if let token::Interpolated(..) = token.kind {
-                        // ^^ Do not `make_mut` unless we have to.
-                        match Lrc::make_mut(&mut tokens.0).get_mut(0) {
-                            Some((TokenTree::Token(token), _spacing)) => match &mut token.kind {
-                                token::Interpolated(nt) => match Lrc::make_mut(nt) {
-                                    token::NtExpr(expr) => vis.visit_expr(expr),
-                                    t => panic!("unexpected token in key-value attribute: {:?}", t),
-                                },
-                                t => panic!("unexpected token in key-value attribute: {:?}", t),
-                            },
+                match Lrc::make_mut(&mut tokens.0).get_mut(0) {
+                    Some((TokenTree::Token(token), _spacing)) => match &mut token.kind {
+                        token::Interpolated(nt) => match Lrc::make_mut(nt) {
+                            token::NtExpr(expr) => vis.visit_expr(expr),
                             t => panic!("unexpected token in key-value attribute: {:?}", t),
-                        }
-                    }
+                        },
+                        t => panic!("unexpected token in key-value attribute: {:?}", t),
+                    },
+                    t => panic!("unexpected token in key-value attribute: {:?}", t),
                 }
             }
         }
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 61426a838de..a420bb56350 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -906,7 +906,6 @@ pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) {
                     token::NtExpr(expr) => visitor.visit_expr(expr),
                     t => panic!("unexpected token in key-value attribute: {:?}", t),
                 },
-                token::Literal(..) | token::Ident(..) => {}
                 t => panic!("unexpected token in key-value attribute: {:?}", t),
             },
             t => panic!("unexpected token in key-value attribute: {:?}", t),
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 5b75fbf339b..9d54d89e080 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -630,6 +630,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
     gate_all!(const_trait_impl, "const trait impls are experimental");
     gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
     gate_all!(inline_const, "inline-const is experimental");
+    gate_all!(
+        extended_key_value_attributes,
+        "arbitrary expressions in key-value attributes are unstable"
+    );
     if sess.parse_sess.span_diagnostic.err_count() == 0 {
         // Errors for `destructuring_assignment` can get quite noisy, especially where `_` is
         // involved, so we only emit errors where there are no other parsing errors.
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 75337634d3f..845e03150d7 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -620,6 +620,9 @@ declare_features! (
     /// Allows capturing disjoint fields in a closure/generator (RFC 2229).
     (active, capture_disjoint_fields, "1.49.0", Some(53488), None),
 
+    /// Allows arbitrary expressions in key-value attributes at parse time.
+    (active, extended_key_value_attributes, "1.50.0", Some(78835), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 22f308ff36d..df4695b18e7 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -23,6 +23,7 @@ use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, E
 use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit};
 use rustc_ast::{Visibility, VisibilityKind};
 use rustc_ast_pretty::pprust;
+use rustc_data_structures::sync::Lrc;
 use rustc_errors::PResult;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError};
 use rustc_session::parse::ParseSess;
@@ -935,16 +936,24 @@ impl<'a> Parser<'a> {
                             is_interpolated_expr = true;
                         }
                     }
-                    let token_tree = if is_interpolated_expr {
-                        // We need to accept arbitrary interpolated expressions to continue
-                        // supporting things like `doc = $expr` that work on stable.
-                        // Non-literal interpolated expressions are rejected after expansion.
-                        self.parse_token_tree()
-                    } else {
-                        self.parse_unsuffixed_lit()?.token_tree()
-                    };
 
-                    MacArgs::Eq(eq_span, token_tree.into())
+                    // The value here is never passed to macros as tokens by itself (not as a part
+                    // of the whole attribute), so we don't collect tokens here. If this changes,
+                    // then token will need to be collected. One catch here is that we are using
+                    // a nonterminal for keeping the expression, but this nonterminal should not
+                    // be wrapped into a group when converting to token stream.
+                    let expr = self.parse_expr()?;
+                    let span = expr.span;
+
+                    match &expr.kind {
+                        // Not gated to supporte things like `doc = $expr` that work on stable.
+                        _ if is_interpolated_expr => {}
+                        ExprKind::Lit(lit) if lit.kind.is_unsuffixed() => {}
+                        _ => self.sess.gated_spans.gate(sym::extended_key_value_attributes, span),
+                    }
+
+                    let token = token::Interpolated(Lrc::new(token::NtExpr(expr)));
+                    MacArgs::Eq(eq_span, TokenTree::token(token, span).into())
                 } else {
                     MacArgs::Empty
                 }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index e75ddb36ff8..b9c942d61a9 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -496,6 +496,7 @@ symbols! {
         expf64,
         export_name,
         expr,
+        extended_key_value_attributes,
         extern_absolute_paths,
         extern_crate_item_prelude,
         extern_crate_self,
diff --git a/src/test/rustdoc/external-doc.rs b/src/test/rustdoc/external-doc.rs
index 4a13f4069c4..befd31a5492 100644
--- a/src/test/rustdoc/external-doc.rs
+++ b/src/test/rustdoc/external-doc.rs
@@ -1,4 +1,5 @@
 #![feature(external_doc)]
+#![feature(extended_key_value_attributes)]
 
 // @has external_doc/struct.CanHasDocs.html
 // @has - '//h1' 'External Docs'
@@ -6,3 +7,18 @@
 #[doc(include = "auxiliary/external-doc.md")]
 /// ## Inline Docs
 pub struct CanHasDocs;
+
+// @has external_doc/struct.IncludeStrDocs.html
+// @has - '//h1' 'External Docs'
+// @has - '//h2' 'Inline Docs'
+#[doc = include_str!("auxiliary/external-doc.md")]
+/// ## Inline Docs
+pub struct IncludeStrDocs;
+
+macro_rules! dir { () => { "auxiliary" } }
+
+// @has external_doc/struct.EagerExpansion.html
+// @has - '//h1' 'External Docs'
+#[doc = include_str!(concat!(dir!(), "/external-doc.md"))]
+/// ## Inline Docs
+pub struct EagerExpansion;
diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout
index b19cfc4d5c3..deb2a1af204 100644
--- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout
+++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":null}]}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout
index 65d6cd475cc..71336f452fc 100644
--- a/src/test/ui/ast-json/ast-json-output.stdout
+++ b/src/test/ui/ast-json/ast-json-output.stdout
@@ -1 +1 @@
-{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
+{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":null}]}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]}
diff --git a/src/test/ui/attr-eq-token-tree.rs b/src/test/ui/attr-eq-token-tree.rs
index c301492b9e2..330b119772a 100644
--- a/src/test/ui/attr-eq-token-tree.rs
+++ b/src/test/ui/attr-eq-token-tree.rs
@@ -1,2 +1,2 @@
-#[my_attr = !] //~ ERROR unexpected token: `!`
+#[my_attr = !] //~ ERROR expected expression, found `]`
 fn main() {}
diff --git a/src/test/ui/attr-eq-token-tree.stderr b/src/test/ui/attr-eq-token-tree.stderr
index bb37c2e0cc4..1846444b668 100644
--- a/src/test/ui/attr-eq-token-tree.stderr
+++ b/src/test/ui/attr-eq-token-tree.stderr
@@ -1,8 +1,8 @@
-error: unexpected token: `!`
-  --> $DIR/attr-eq-token-tree.rs:1:13
+error: expected expression, found `]`
+  --> $DIR/attr-eq-token-tree.rs:1:14
    |
 LL | #[my_attr = !]
-   |             ^
+   |              ^ expected expression
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/attributes/key-value-expansion.rs b/src/test/ui/attributes/key-value-expansion.rs
index 831c8091f32..08121413ee9 100644
--- a/src/test/ui/attributes/key-value-expansion.rs
+++ b/src/test/ui/attributes/key-value-expansion.rs
@@ -12,23 +12,22 @@ extern crate key_value_expansion;
 macro_rules! bug {
     ($expr:expr) => {
         #[rustc_dummy = $expr] // Any key-value attribute, not necessarily `doc`
-        //~^ ERROR unexpected token: `(7u32)`
         struct S;
     };
 }
 
 // Any expressions containing macro call `X` that's more complex than `X` itself.
 // Parentheses will work.
-bug!((column!()));
+bug!((column!())); //~ ERROR unexpected token: `(7u32)`
 
 // Original test case.
 
 macro_rules! bug {
     () => {
-        bug!("bug" + stringify!(found));
+        bug!("bug" + stringify!(found)); //~ ERROR unexpected token: `"bug" + "found"`
     };
     ($test:expr) => {
-        #[doc = $test] //~ ERROR unexpected token: `"bug" + "found"`
+        #[doc = $test]
         struct Test {}
     };
 }
@@ -39,7 +38,7 @@ bug!();
 
 macro_rules! doc_comment {
     ($x:expr) => {
-        #[doc = $x] //~ ERROR unexpected token: `{
+        #[doc = $x]
         extern {}
     };
 }
@@ -47,6 +46,7 @@ macro_rules! doc_comment {
 macro_rules! some_macro {
     ($t1: ty) => {
         doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()}
+        //~^ ERROR unexpected token: `{
     };
 }
 
diff --git a/src/test/ui/attributes/key-value-expansion.stderr b/src/test/ui/attributes/key-value-expansion.stderr
index 5da4557f0ae..4b14b88a74f 100644
--- a/src/test/ui/attributes/key-value-expansion.stderr
+++ b/src/test/ui/attributes/key-value-expansion.stderr
@@ -1,19 +1,14 @@
 error: unexpected token: `(7u32)`
-  --> $DIR/key-value-expansion.rs:14:25
+  --> $DIR/key-value-expansion.rs:21:6
    |
-LL |         #[rustc_dummy = $expr] // Any key-value attribute, not necessarily `doc`
-   |                         ^^^^^
-...
 LL | bug!((column!()));
-   | ------------------ in this macro invocation
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+   |      ^^^^^^^^^^^
 
 error: unexpected token: `"bug" + "found"`
-  --> $DIR/key-value-expansion.rs:31:17
+  --> $DIR/key-value-expansion.rs:27:14
    |
-LL |         #[doc = $test]
-   |                 ^^^^^
+LL |         bug!("bug" + stringify!(found));
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL | bug!();
    | ------- in this macro invocation
@@ -30,10 +25,10 @@ error: unexpected token: `{
                                                              }));
     res
 }.as_str()`
-  --> $DIR/key-value-expansion.rs:42:17
+  --> $DIR/key-value-expansion.rs:48:23
    |
-LL |         #[doc = $x]
-   |                 ^^
+LL |         doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()}
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL | some_macro!(u8);
    | ---------------- in this macro invocation
diff --git a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs
new file mode 100644
index 00000000000..f19fdb45f1f
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs
@@ -0,0 +1,8 @@
+#[cfg(FALSE)]
+#[attr = multi::segment::path] //~ ERROR arbitrary expressions in key-value attributes are unstable
+#[attr = macro_call!()] //~ ERROR arbitrary expressions in key-value attributes are unstable
+#[attr = 1 + 2] //~ ERROR arbitrary expressions in key-value attributes are unstable
+#[attr = what?] //~ ERROR arbitrary expressions in key-value attributes are unstable
+struct S;
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr
new file mode 100644
index 00000000000..9887814b907
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr
@@ -0,0 +1,39 @@
+error[E0658]: arbitrary expressions in key-value attributes are unstable
+  --> $DIR/feature-gate-extended_key_value_attributes.rs:2:10
+   |
+LL | #[attr = multi::segment::path]
+   |          ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information
+   = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable
+
+error[E0658]: arbitrary expressions in key-value attributes are unstable
+  --> $DIR/feature-gate-extended_key_value_attributes.rs:3:10
+   |
+LL | #[attr = macro_call!()]
+   |          ^^^^^^^^^^^^^
+   |
+   = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information
+   = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable
+
+error[E0658]: arbitrary expressions in key-value attributes are unstable
+  --> $DIR/feature-gate-extended_key_value_attributes.rs:4:10
+   |
+LL | #[attr = 1 + 2]
+   |          ^^^^^
+   |
+   = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information
+   = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable
+
+error[E0658]: arbitrary expressions in key-value attributes are unstable
+  --> $DIR/feature-gate-extended_key_value_attributes.rs:5:10
+   |
+LL | #[attr = what?]
+   |          ^^^^^
+   |
+   = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information
+   = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/macros/macro-attribute.rs b/src/test/ui/macros/macro-attribute.rs
index f580dfa8e34..88834a96721 100644
--- a/src/test/ui/macros/macro-attribute.rs
+++ b/src/test/ui/macros/macro-attribute.rs
@@ -1,2 +1,2 @@
-#[doc = $not_there] //~ ERROR unexpected token: `$`
+#[doc = $not_there] //~ ERROR expected expression, found `$`
 fn main() { }
diff --git a/src/test/ui/macros/macro-attribute.stderr b/src/test/ui/macros/macro-attribute.stderr
index d28ce25341d..3316d387264 100644
--- a/src/test/ui/macros/macro-attribute.stderr
+++ b/src/test/ui/macros/macro-attribute.stderr
@@ -1,8 +1,8 @@
-error: unexpected token: `$`
+error: expected expression, found `$`
   --> $DIR/macro-attribute.rs:1:9
    |
 LL | #[doc = $not_there]
-   |         ^
+   |         ^ expected expression
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/malformed/malformed-interpolated.rs b/src/test/ui/malformed/malformed-interpolated.rs
index 5101b5caeea..b962447e7ed 100644
--- a/src/test/ui/malformed/malformed-interpolated.rs
+++ b/src/test/ui/malformed/malformed-interpolated.rs
@@ -2,8 +2,7 @@
 
 macro_rules! check {
     ($expr: expr) => (
-        #[rustc_dummy = $expr] //~ ERROR unexpected token: `-0`
-                               //~| ERROR unexpected token: `0 + 0`
+        #[rustc_dummy = $expr]
         use main as _;
     );
 }
@@ -11,7 +10,7 @@ macro_rules! check {
 check!("0"); // OK
 check!(0); // OK
 check!(0u8); //~ ERROR suffixed literals are not allowed in attributes
-check!(-0); // ERROR, see above
-check!(0 + 0); // ERROR, see above
+check!(-0); //~ ERROR unexpected token: `-0`
+check!(0 + 0); //~ ERROR unexpected token: `0 + 0`
 
 fn main() {}
diff --git a/src/test/ui/malformed/malformed-interpolated.stderr b/src/test/ui/malformed/malformed-interpolated.stderr
index d1be82cf7b7..4b9332ddd01 100644
--- a/src/test/ui/malformed/malformed-interpolated.stderr
+++ b/src/test/ui/malformed/malformed-interpolated.stderr
@@ -1,5 +1,5 @@
 error: suffixed literals are not allowed in attributes
-  --> $DIR/malformed-interpolated.rs:13:8
+  --> $DIR/malformed-interpolated.rs:12:8
    |
 LL | check!(0u8);
    |        ^^^
@@ -7,26 +7,16 @@ LL | check!(0u8);
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: unexpected token: `-0`
-  --> $DIR/malformed-interpolated.rs:5:25
+  --> $DIR/malformed-interpolated.rs:13:8
    |
-LL |         #[rustc_dummy = $expr]
-   |                         ^^^^^
-...
-LL | check!(-0); // ERROR, see above
-   | ----------- in this macro invocation
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | check!(-0);
+   |        ^^
 
 error: unexpected token: `0 + 0`
-  --> $DIR/malformed-interpolated.rs:5:25
+  --> $DIR/malformed-interpolated.rs:14:8
    |
-LL |         #[rustc_dummy = $expr]
-   |                         ^^^^^
-...
-LL | check!(0 + 0); // ERROR, see above
-   | -------------- in this macro invocation
-   |
-   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+LL | check!(0 + 0);
+   |        ^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/parser/attr-bad-meta-2.rs b/src/test/ui/parser/attr-bad-meta-2.rs
index cefd3369742..db612ed883d 100644
--- a/src/test/ui/parser/attr-bad-meta-2.rs
+++ b/src/test/ui/parser/attr-bad-meta-2.rs
@@ -1,2 +1,2 @@
-#[path =] //~ ERROR unexpected token: `]`
+#[path =] //~ ERROR expected expression, found `]`
 mod m {}
diff --git a/src/test/ui/parser/attr-bad-meta-2.stderr b/src/test/ui/parser/attr-bad-meta-2.stderr
index 2d772dae691..6fc6fb665a8 100644
--- a/src/test/ui/parser/attr-bad-meta-2.stderr
+++ b/src/test/ui/parser/attr-bad-meta-2.stderr
@@ -1,8 +1,8 @@
-error: unexpected token: `]`
+error: expected expression, found `]`
   --> $DIR/attr-bad-meta-2.rs:1:9
    |
 LL | #[path =]
-   |         ^
+   |         ^ expected expression
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suffixed-literal-meta.rs b/src/test/ui/suffixed-literal-meta.rs
index c3a4eabad70..319264aec9c 100644
--- a/src/test/ui/suffixed-literal-meta.rs
+++ b/src/test/ui/suffixed-literal-meta.rs
@@ -1,27 +1,15 @@
-#![feature(rustc_attrs)]
+#![feature(rustc_attrs, extended_key_value_attributes)]
 
 #[rustc_dummy = 1usize] //~ ERROR: suffixed literals are not allowed in attributes
-                        //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1u8] //~ ERROR: suffixed literals are not allowed in attributes
-                     //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1u16] //~ ERROR: suffixed literals are not allowed in attributes
-                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1u32] //~ ERROR: suffixed literals are not allowed in attributes
-                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1u64] //~ ERROR: suffixed literals are not allowed in attributes
-                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1isize] //~ ERROR: suffixed literals are not allowed in attributes
-                        //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1i8] //~ ERROR: suffixed literals are not allowed in attributes
-                     //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1i16] //~ ERROR: suffixed literals are not allowed in attributes
-                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1i32] //~ ERROR: suffixed literals are not allowed in attributes
-                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1i64] //~ ERROR: suffixed literals are not allowed in attributes
-                      //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1.0f32] //~ ERROR: suffixed literals are not allowed in attributes
-                        //~| ERROR: suffixed literals are not allowed in attributes
 #[rustc_dummy = 1.0f64] //~ ERROR: suffixed literals are not allowed in attributes
-                        //~| ERROR: suffixed literals are not allowed in attributes
 fn main() {}
diff --git a/src/test/ui/suffixed-literal-meta.stderr b/src/test/ui/suffixed-literal-meta.stderr
index 84fe91d662a..5245ffead71 100644
--- a/src/test/ui/suffixed-literal-meta.stderr
+++ b/src/test/ui/suffixed-literal-meta.stderr
@@ -7,119 +7,23 @@ LL | #[rustc_dummy = 1usize]
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:5:17
+  --> $DIR/suffixed-literal-meta.rs:4:17
    |
 LL | #[rustc_dummy = 1u8]
    |                 ^^^
    |
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:7:17
-   |
-LL | #[rustc_dummy = 1u16]
-   |                 ^^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:9:17
-   |
-LL | #[rustc_dummy = 1u32]
-   |                 ^^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:11:17
-   |
-LL | #[rustc_dummy = 1u64]
-   |                 ^^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:13:17
-   |
-LL | #[rustc_dummy = 1isize]
-   |                 ^^^^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:15:17
-   |
-LL | #[rustc_dummy = 1i8]
-   |                 ^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:17:17
-   |
-LL | #[rustc_dummy = 1i16]
-   |                 ^^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:19:17
-   |
-LL | #[rustc_dummy = 1i32]
-   |                 ^^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:21:17
-   |
-LL | #[rustc_dummy = 1i64]
-   |                 ^^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:23:17
-   |
-LL | #[rustc_dummy = 1.0f32]
-   |                 ^^^^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:25:17
-   |
-LL | #[rustc_dummy = 1.0f64]
-   |                 ^^^^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:3:17
-   |
-LL | #[rustc_dummy = 1usize]
-   |                 ^^^^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
 error: suffixed literals are not allowed in attributes
   --> $DIR/suffixed-literal-meta.rs:5:17
    |
-LL | #[rustc_dummy = 1u8]
-   |                 ^^^
-   |
-   = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:7:17
-   |
 LL | #[rustc_dummy = 1u16]
    |                 ^^^^
    |
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:9:17
+  --> $DIR/suffixed-literal-meta.rs:6:17
    |
 LL | #[rustc_dummy = 1u32]
    |                 ^^^^
@@ -127,7 +31,7 @@ LL | #[rustc_dummy = 1u32]
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:11:17
+  --> $DIR/suffixed-literal-meta.rs:7:17
    |
 LL | #[rustc_dummy = 1u64]
    |                 ^^^^
@@ -135,7 +39,7 @@ LL | #[rustc_dummy = 1u64]
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:13:17
+  --> $DIR/suffixed-literal-meta.rs:8:17
    |
 LL | #[rustc_dummy = 1isize]
    |                 ^^^^^^
@@ -143,7 +47,7 @@ LL | #[rustc_dummy = 1isize]
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:15:17
+  --> $DIR/suffixed-literal-meta.rs:9:17
    |
 LL | #[rustc_dummy = 1i8]
    |                 ^^^
@@ -151,7 +55,7 @@ LL | #[rustc_dummy = 1i8]
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:17:17
+  --> $DIR/suffixed-literal-meta.rs:10:17
    |
 LL | #[rustc_dummy = 1i16]
    |                 ^^^^
@@ -159,7 +63,7 @@ LL | #[rustc_dummy = 1i16]
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:19:17
+  --> $DIR/suffixed-literal-meta.rs:11:17
    |
 LL | #[rustc_dummy = 1i32]
    |                 ^^^^
@@ -167,7 +71,7 @@ LL | #[rustc_dummy = 1i32]
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:21:17
+  --> $DIR/suffixed-literal-meta.rs:12:17
    |
 LL | #[rustc_dummy = 1i64]
    |                 ^^^^
@@ -175,7 +79,7 @@ LL | #[rustc_dummy = 1i64]
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:23:17
+  --> $DIR/suffixed-literal-meta.rs:13:17
    |
 LL | #[rustc_dummy = 1.0f32]
    |                 ^^^^^^
@@ -183,12 +87,12 @@ LL | #[rustc_dummy = 1.0f32]
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
 error: suffixed literals are not allowed in attributes
-  --> $DIR/suffixed-literal-meta.rs:25:17
+  --> $DIR/suffixed-literal-meta.rs:14:17
    |
 LL | #[rustc_dummy = 1.0f64]
    |                 ^^^^^^
    |
    = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
 
-error: aborting due to 24 previous errors
+error: aborting due to 12 previous errors