Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,15 @@ fn parse_derive_like<S: Stage>(
return None;
};

// updated if we see `attributes(...)` to keep track of the last
// argument we did accept for the final diagnostic
let mut last = trait_ident.span;

// Parse optional attributes
let mut attributes = ThinVec::new();
if let Some(attrs) = items.next() {
last = attrs.span();

let Some(attr_list) = attrs.meta_item() else {
cx.expected_list(attrs.span());
return None;
Expand Down Expand Up @@ -132,7 +138,7 @@ fn parse_derive_like<S: Stage>(

// If anything else is specified, we should reject it
if let Some(next) = items.next() {
cx.expected_no_args(next.span());
cx.expected_end_of_list(last, next.span());
}

Some((Some(trait_ident.name), attributes))
Expand Down
15 changes: 15 additions & 0 deletions compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,21 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
})
}

/// Expected the end of an argument list.
///
/// Note: only useful when arguments in an attribute are ordered and we've seen the last one we expected.
/// Most attributes shouldn't care about their argument order.
pub(crate) fn expected_end_of_list(&self, last_item_span: Span, span: Span) -> ErrorGuaranteed {
self.emit_err(AttributeParseError {
span,
attr_span: self.attr_span,
template: self.template.clone(),
attribute: self.attr_path.clone(),
reason: AttributeParseErrorReason::ExpectedEnd { last: last_item_span },
attr_style: self.attr_style,
})
}

pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
self.emit_err(AttributeParseError {
span,
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,9 @@ pub(crate) enum AttributeParseErrorReason<'a> {
list: bool,
},
ExpectedIdentifier,
ExpectedEnd {
last: Span,
},
}

pub(crate) struct AttributeParseError<'a> {
Expand Down Expand Up @@ -744,6 +747,10 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
AttributeParseErrorReason::ExpectedIdentifier => {
diag.span_label(self.span, "expected a valid identifier here");
}
AttributeParseErrorReason::ExpectedEnd { last } => {
diag.span_label(last, "expected no more arguments after this");
diag.span_label(self.span, "remove this argument");
}
}

if let Some(link) = self.template.docs {
Expand Down
71 changes: 53 additions & 18 deletions tests/ui/proc-macro/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,97 +10,132 @@ use proc_macro::*;
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE expected this to be a list
//~| NOTE for more information, visit
pub fn foo1(input: TokenStream) -> TokenStream { input }
pub fn foo1(input: TokenStream) -> TokenStream {
input
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you undo the reformatting of this file? Files within tests/ui/ aren't auto-formatted, and it's just churn that obscures the actual change in this commit.


#[proc_macro_derive = ""]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE expected this to be a list
//~| NOTE for more information, visit
pub fn foo2(input: TokenStream) -> TokenStream { input }
pub fn foo2(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(d3, a, b)]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE the only valid argument here is `attributes`
//~| NOTE for more information, visit
pub fn foo3(input: TokenStream) -> TokenStream { input }
pub fn foo3(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(d4, attributes(a), b)]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE didn't expect any arguments here
//~| NOTE expected no more arguments after this
//~| NOTE remove this argument
//~| NOTE for more information, visit
pub fn foo4(input: TokenStream) -> TokenStream { input }
pub fn foo4(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive("a")]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE didn't expect a literal here
//~| NOTE for more information, visit
pub fn foo5(input: TokenStream) -> TokenStream { input }
pub fn foo5(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(d6 = "")]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE didn't expect any arguments here
//~| NOTE for more information, visit
pub fn foo6(input: TokenStream) -> TokenStream { input }
pub fn foo6(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(m::d7)]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE expected a valid identifier here
//~| NOTE for more information, visit
pub fn foo7(input: TokenStream) -> TokenStream { input }
pub fn foo7(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(d8(a))]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE didn't expect any arguments here
//~| NOTE for more information, visit
pub fn foo8(input: TokenStream) -> TokenStream { input }
pub fn foo8(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(self)]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE expected a valid identifier here
//~| NOTE for more information, visit
pub fn foo9(input: TokenStream) -> TokenStream { input }
pub fn foo9(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(PartialEq)] // OK
pub fn foo10(input: TokenStream) -> TokenStream { input }
pub fn foo10(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(d11, a)]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE the only valid argument here is `attributes`
//~| NOTE for more information, visit
pub fn foo11(input: TokenStream) -> TokenStream { input }
pub fn foo11(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(d12, attributes)]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE expected this to be a list
//~| NOTE for more information, visit
pub fn foo12(input: TokenStream) -> TokenStream { input }
pub fn foo12(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(d13, attributes("a"))]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE expected a valid identifier here
//~| NOTE for more information, visit
pub fn foo13(input: TokenStream) -> TokenStream { input }
pub fn foo13(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(d14, attributes(a = ""))]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE didn't expect any arguments here
//~| NOTE for more information, visit
pub fn foo14(input: TokenStream) -> TokenStream { input }
pub fn foo14(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(d15, attributes(m::a))]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE expected a valid identifier here
//~| NOTE for more information, visit
pub fn foo15(input: TokenStream) -> TokenStream { input }
pub fn foo15(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(d16, attributes(a(b)))]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE didn't expect any arguments here
//~| NOTE for more information, visit
pub fn foo16(input: TokenStream) -> TokenStream { input }
pub fn foo16(input: TokenStream) -> TokenStream {
input
}

#[proc_macro_derive(d17, attributes(self))]
//~^ ERROR malformed `proc_macro_derive` attribute
//~| NOTE expected a valid identifier here
//~| NOTE for more information, visit
pub fn foo17(input: TokenStream) -> TokenStream { input }
pub fn foo17(input: TokenStream) -> TokenStream {
input
}
39 changes: 20 additions & 19 deletions tests/ui/proc-macro/attribute.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ LL | #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
| ++++++++++++++++++++++++++++++++++++++++++

error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:15:1
--> $DIR/attribute.rs:17:1
|
LL | #[proc_macro_derive = ""]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected this to be a list
Expand All @@ -29,7 +29,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:21:1
--> $DIR/attribute.rs:25:1
|
LL | #[proc_macro_derive(d3, a, b)]
| ^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^
Expand All @@ -46,13 +46,14 @@ LL - #[proc_macro_derive(d3, a, b)]
LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0565]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:27:1
error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:33:1
|
LL | #[proc_macro_derive(d4, attributes(a), b)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
| |
| didn't expect any arguments here
| ^^^^^^^^^^^^^^^^^^^^^^^^-------------^^-^^
| | |
| | remove this argument
| expected no more arguments after this
|
= note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
help: try changing it to one of the following valid forms of the attribute
Expand All @@ -65,7 +66,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0565]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:33:1
--> $DIR/attribute.rs:42:1
|
LL | #[proc_macro_derive("a")]
| ^^^^^^^^^^^^^^^^^^^^---^^
Expand All @@ -83,7 +84,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0565]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:39:1
--> $DIR/attribute.rs:50:1
|
LL | #[proc_macro_derive(d6 = "")]
| ^^^^^^^^^^^^^^^^^^^^^^^----^^
Expand All @@ -101,7 +102,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:45:1
--> $DIR/attribute.rs:58:1
|
LL | #[proc_macro_derive(m::d7)]
| ^^^^^^^^^^^^^^^^^^^^-----^^
Expand All @@ -119,7 +120,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0565]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:51:1
--> $DIR/attribute.rs:66:1
|
LL | #[proc_macro_derive(d8(a))]
| ^^^^^^^^^^^^^^^^^^^^^^---^^
Expand All @@ -137,7 +138,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:57:1
--> $DIR/attribute.rs:74:1
|
LL | #[proc_macro_derive(self)]
| ^^^^^^^^^^^^^^^^^^^^----^^
Expand All @@ -155,7 +156,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:66:1
--> $DIR/attribute.rs:87:1
|
LL | #[proc_macro_derive(d11, a)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^-^^
Expand All @@ -173,7 +174,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:72:1
--> $DIR/attribute.rs:95:1
|
LL | #[proc_macro_derive(d12, attributes)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^----------^^
Expand All @@ -191,7 +192,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:78:1
--> $DIR/attribute.rs:103:1
|
LL | #[proc_macro_derive(d13, attributes("a"))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^
Expand All @@ -209,7 +210,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0565]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:84:1
--> $DIR/attribute.rs:111:1
|
LL | #[proc_macro_derive(d14, attributes(a = ""))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
Expand All @@ -227,7 +228,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:90:1
--> $DIR/attribute.rs:119:1
|
LL | #[proc_macro_derive(d15, attributes(m::a))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
Expand All @@ -245,7 +246,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0565]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:96:1
--> $DIR/attribute.rs:127:1
|
LL | #[proc_macro_derive(d16, attributes(a(b)))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^
Expand All @@ -263,7 +264,7 @@ LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
|

error[E0539]: malformed `proc_macro_derive` attribute input
--> $DIR/attribute.rs:102:1
--> $DIR/attribute.rs:135:1
|
LL | #[proc_macro_derive(d17, attributes(self))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
Expand Down
Loading