Skip to content

Commit 58d2bad

Browse files
committed
Auto merge of #78837 - petrochenkov:keyvalexpr, r=davidtwco
Accept arbitrary expressions in key-value attributes at parse time Continuation of #77271. We now support arbitrary expressions in values of key-value attributes at parse time. ``` #[my_attr = EXPR] ``` Previously only unsuffixed literals and interpolated expressions (`$expr`) were accepted. There are two immediate motivational cases for this: - External doc strings (`#[doc = include_str!("my_doc.md")]`, eliminating the need in #44732) and expanding macros in this position in general. Currently such macro expansions are supported in this position in interpolated `$expr`s (the `#[doc = $doc]` idiom). - Paths (`#[namespace = foo::bar] extern "C++" { ... }`) like proposed in #76734. If the attribute in question survives expansion, then the value is still restricted to unsuffixed literals by a semantic check. This restriction doesn't prevent the use cases listed above, so this PR keeps it in place for now. Closes #52607. Previous attempt - #67121. Some more detailed write up on internals - https://internals.rust-lang.org/t/macro-expansion-points-in-attributes/11455. Tracking issue - #78835.
2 parents 1cc4107 + 31d72c2 commit 58d2bad

24 files changed

+145
-210
lines changed

compiler/rustc_ast/src/ast.rs

+1-16
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub use UnsafeSource::*;
2424

2525
use crate::ptr::P;
2626
use crate::token::{self, CommentKind, DelimToken};
27-
use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree};
27+
use crate::tokenstream::{DelimSpan, LazyTokenStream, TokenStream};
2828

2929
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
3030
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -39,7 +39,6 @@ use rustc_span::{Span, DUMMY_SP};
3939
use std::cmp::Ordering;
4040
use std::convert::TryFrom;
4141
use std::fmt;
42-
use std::iter;
4342

4443
#[cfg(test)]
4544
mod tests;
@@ -1514,20 +1513,6 @@ impl MacArgs {
15141513
}
15151514
}
15161515

1517-
/// Tokens together with the delimiters or `=`.
1518-
/// Use of this method generally means that something suboptimal or hacky is happening.
1519-
pub fn outer_tokens(&self) -> TokenStream {
1520-
match *self {
1521-
MacArgs::Empty => TokenStream::default(),
1522-
MacArgs::Delimited(dspan, delim, ref tokens) => {
1523-
TokenTree::Delimited(dspan, delim.to_token(), tokens.clone()).into()
1524-
}
1525-
MacArgs::Eq(eq_span, ref tokens) => {
1526-
iter::once(TokenTree::token(token::Eq, eq_span)).chain(tokens.trees()).collect()
1527-
}
1528-
}
1529-
}
1530-
15311516
/// Whether a macro with these arguments needs a semicolon
15321517
/// when used as a standalone item or statement.
15331518
pub fn need_semicolon(&self) -> bool {

compiler/rustc_ast/src/mut_visit.rs

+8-13
Original file line numberDiff line numberDiff line change
@@ -371,20 +371,15 @@ pub fn visit_mac_args<T: MutVisitor>(args: &mut MacArgs, vis: &mut T) {
371371
// The value in `#[key = VALUE]` must be visited as an expression for backward
372372
// compatibility, so that macros can be expanded in that position.
373373
if !vis.token_visiting_enabled() {
374-
if let Some(TokenTree::Token(token)) = tokens.trees_ref().next() {
375-
if let token::Interpolated(..) = token.kind {
376-
// ^^ Do not `make_mut` unless we have to.
377-
match Lrc::make_mut(&mut tokens.0).get_mut(0) {
378-
Some((TokenTree::Token(token), _spacing)) => match &mut token.kind {
379-
token::Interpolated(nt) => match Lrc::make_mut(nt) {
380-
token::NtExpr(expr) => vis.visit_expr(expr),
381-
t => panic!("unexpected token in key-value attribute: {:?}", t),
382-
},
383-
t => panic!("unexpected token in key-value attribute: {:?}", t),
384-
},
374+
match Lrc::make_mut(&mut tokens.0).get_mut(0) {
375+
Some((TokenTree::Token(token), _spacing)) => match &mut token.kind {
376+
token::Interpolated(nt) => match Lrc::make_mut(nt) {
377+
token::NtExpr(expr) => vis.visit_expr(expr),
385378
t => panic!("unexpected token in key-value attribute: {:?}", t),
386-
}
387-
}
379+
},
380+
t => panic!("unexpected token in key-value attribute: {:?}", t),
381+
},
382+
t => panic!("unexpected token in key-value attribute: {:?}", t),
388383
}
389384
}
390385
}

compiler/rustc_ast/src/visit.rs

-1
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,6 @@ pub fn walk_mac_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a MacArgs) {
906906
token::NtExpr(expr) => visitor.visit_expr(expr),
907907
t => panic!("unexpected token in key-value attribute: {:?}", t),
908908
},
909-
token::Literal(..) | token::Ident(..) => {}
910909
t => panic!("unexpected token in key-value attribute: {:?}", t),
911910
},
912911
t => panic!("unexpected token in key-value attribute: {:?}", t),

compiler/rustc_ast_passes/src/feature_gate.rs

+4
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,10 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
630630
gate_all!(const_trait_impl, "const trait impls are experimental");
631631
gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
632632
gate_all!(inline_const, "inline-const is experimental");
633+
gate_all!(
634+
extended_key_value_attributes,
635+
"arbitrary expressions in key-value attributes are unstable"
636+
);
633637
if sess.parse_sess.span_diagnostic.err_count() == 0 {
634638
// Errors for `destructuring_assignment` can get quite noisy, especially where `_` is
635639
// involved, so we only emit errors where there are no other parsing errors.

compiler/rustc_feature/src/active.rs

+3
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,9 @@ declare_features! (
620620
/// Allows capturing disjoint fields in a closure/generator (RFC 2229).
621621
(active, capture_disjoint_fields, "1.49.0", Some(53488), None),
622622

623+
/// Allows arbitrary expressions in key-value attributes at parse time.
624+
(active, extended_key_value_attributes, "1.50.0", Some(78835), None),
625+
623626
// -------------------------------------------------------------------------
624627
// feature-group-end: actual feature gates
625628
// -------------------------------------------------------------------------

compiler/rustc_parse/src/parser/mod.rs

+18-9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, CrateSugar, E
2323
use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacDelimiter, Mutability, StrLit};
2424
use rustc_ast::{Visibility, VisibilityKind};
2525
use rustc_ast_pretty::pprust;
26+
use rustc_data_structures::sync::Lrc;
2627
use rustc_errors::PResult;
2728
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError};
2829
use rustc_session::parse::ParseSess;
@@ -935,16 +936,24 @@ impl<'a> Parser<'a> {
935936
is_interpolated_expr = true;
936937
}
937938
}
938-
let token_tree = if is_interpolated_expr {
939-
// We need to accept arbitrary interpolated expressions to continue
940-
// supporting things like `doc = $expr` that work on stable.
941-
// Non-literal interpolated expressions are rejected after expansion.
942-
self.parse_token_tree()
943-
} else {
944-
self.parse_unsuffixed_lit()?.token_tree()
945-
};
946939

947-
MacArgs::Eq(eq_span, token_tree.into())
940+
// The value here is never passed to macros as tokens by itself (not as a part
941+
// of the whole attribute), so we don't collect tokens here. If this changes,
942+
// then token will need to be collected. One catch here is that we are using
943+
// a nonterminal for keeping the expression, but this nonterminal should not
944+
// be wrapped into a group when converting to token stream.
945+
let expr = self.parse_expr()?;
946+
let span = expr.span;
947+
948+
match &expr.kind {
949+
// Not gated to supporte things like `doc = $expr` that work on stable.
950+
_ if is_interpolated_expr => {}
951+
ExprKind::Lit(lit) if lit.kind.is_unsuffixed() => {}
952+
_ => self.sess.gated_spans.gate(sym::extended_key_value_attributes, span),
953+
}
954+
955+
let token = token::Interpolated(Lrc::new(token::NtExpr(expr)));
956+
MacArgs::Eq(eq_span, TokenTree::token(token, span).into())
948957
} else {
949958
MacArgs::Empty
950959
}

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,7 @@ symbols! {
496496
expf64,
497497
export_name,
498498
expr,
499+
extended_key_value_attributes,
499500
extern_absolute_paths,
500501
extern_crate_item_prelude,
501502
extern_crate_self,

src/test/rustdoc/external-doc.rs

+16
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
11
#![feature(external_doc)]
2+
#![feature(extended_key_value_attributes)]
23

34
// @has external_doc/struct.CanHasDocs.html
45
// @has - '//h1' 'External Docs'
56
// @has - '//h2' 'Inline Docs'
67
#[doc(include = "auxiliary/external-doc.md")]
78
/// ## Inline Docs
89
pub struct CanHasDocs;
10+
11+
// @has external_doc/struct.IncludeStrDocs.html
12+
// @has - '//h1' 'External Docs'
13+
// @has - '//h2' 'Inline Docs'
14+
#[doc = include_str!("auxiliary/external-doc.md")]
15+
/// ## Inline Docs
16+
pub struct IncludeStrDocs;
17+
18+
macro_rules! dir { () => { "auxiliary" } }
19+
20+
// @has external_doc/struct.EagerExpansion.html
21+
// @has - '//h1' 'External Docs'
22+
#[doc = include_str!(concat!(dir!(), "/external-doc.md"))]
23+
/// ## Inline Docs
24+
pub struct EagerExpansion;
Original file line numberDiff line numberDiff line change
@@ -1 +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":[]}
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":"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":[]}
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +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":[]}
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":"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":[]}

src/test/ui/attr-eq-token-tree.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
#[my_attr = !] //~ ERROR unexpected token: `!`
1+
#[my_attr = !] //~ ERROR expected expression, found `]`
22
fn main() {}

src/test/ui/attr-eq-token-tree.stderr

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: unexpected token: `!`
2-
--> $DIR/attr-eq-token-tree.rs:1:13
1+
error: expected expression, found `]`
2+
--> $DIR/attr-eq-token-tree.rs:1:14
33
|
44
LL | #[my_attr = !]
5-
| ^
5+
| ^ expected expression
66

77
error: aborting due to previous error
88

src/test/ui/attributes/key-value-expansion.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,22 @@ extern crate key_value_expansion;
1212
macro_rules! bug {
1313
($expr:expr) => {
1414
#[rustc_dummy = $expr] // Any key-value attribute, not necessarily `doc`
15-
//~^ ERROR unexpected token: `(7u32)`
1615
struct S;
1716
};
1817
}
1918

2019
// Any expressions containing macro call `X` that's more complex than `X` itself.
2120
// Parentheses will work.
22-
bug!((column!()));
21+
bug!((column!())); //~ ERROR unexpected token: `(7u32)`
2322

2423
// Original test case.
2524

2625
macro_rules! bug {
2726
() => {
28-
bug!("bug" + stringify!(found));
27+
bug!("bug" + stringify!(found)); //~ ERROR unexpected token: `"bug" + "found"`
2928
};
3029
($test:expr) => {
31-
#[doc = $test] //~ ERROR unexpected token: `"bug" + "found"`
30+
#[doc = $test]
3231
struct Test {}
3332
};
3433
}
@@ -39,14 +38,15 @@ bug!();
3938

4039
macro_rules! doc_comment {
4140
($x:expr) => {
42-
#[doc = $x] //~ ERROR unexpected token: `{
41+
#[doc = $x]
4342
extern {}
4443
};
4544
}
4645

4746
macro_rules! some_macro {
4847
($t1: ty) => {
4948
doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()}
49+
//~^ ERROR unexpected token: `{
5050
};
5151
}
5252

src/test/ui/attributes/key-value-expansion.stderr

+8-13
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
error: unexpected token: `(7u32)`
2-
--> $DIR/key-value-expansion.rs:14:25
2+
--> $DIR/key-value-expansion.rs:21:6
33
|
4-
LL | #[rustc_dummy = $expr] // Any key-value attribute, not necessarily `doc`
5-
| ^^^^^
6-
...
74
LL | bug!((column!()));
8-
| ------------------ in this macro invocation
9-
|
10-
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
5+
| ^^^^^^^^^^^
116

127
error: unexpected token: `"bug" + "found"`
13-
--> $DIR/key-value-expansion.rs:31:17
8+
--> $DIR/key-value-expansion.rs:27:14
149
|
15-
LL | #[doc = $test]
16-
| ^^^^^
10+
LL | bug!("bug" + stringify!(found));
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
1712
...
1813
LL | bug!();
1914
| ------- in this macro invocation
@@ -30,10 +25,10 @@ error: unexpected token: `{
3025
}));
3126
res
3227
}.as_str()`
33-
--> $DIR/key-value-expansion.rs:42:17
28+
--> $DIR/key-value-expansion.rs:48:23
3429
|
35-
LL | #[doc = $x]
36-
| ^^
30+
LL | doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()}
31+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3732
...
3833
LL | some_macro!(u8);
3934
| ---------------- in this macro invocation

0 commit comments

Comments
 (0)