Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
392 changes: 381 additions & 11 deletions src/serde_tokenstream.rs

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions testlib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,24 @@ pub fn rejected(
}
}

// Fixture for TokenStreamWrapper values.
#[derive(Deserialize)]
#[allow(dead_code)]
struct Tokens {
tokens: serde_tokenstream::TokenStreamWrapper,
}

#[proc_macro_attribute]
pub fn tokens(
attr: proc_macro::TokenStream,
item: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
match from_tokenstream::<Tokens>(&attr.into()) {
Ok(_) => item,
Err(err) => err.to_compile_error().into(),
}
}

#[proc_macro_attribute]
pub fn outer(
_attr: proc_macro::TokenStream,
Expand Down
23 changes: 23 additions & 0 deletions ui-tests/tests/ui/bad_parse_wrapper_from_macro_rules_empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2026 Oxide Computer Company

// An empty macro_rules substitution into a ParseWrapper must produce a
// missing-value error, similar to plain values.

use testlib::annotation;

macro_rules! wrap {
($v:vis ,) => {
#[annotation {
string = "test",
options = OptionA,
unit = (),
tup = (1, 2.0),
bool_expr = $v,
}]
fn test() {}
};
}

wrap!(,);

fn main() {}
10 changes: 10 additions & 0 deletions ui-tests/tests/ui/bad_parse_wrapper_from_macro_rules_empty.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: expected a value, but found `,`
--> tests/ui/bad_parse_wrapper_from_macro_rules_empty.rs:15:27
|
15 | bool_expr = $v,
| ^
...
21 | wrap!(,);
| -------- in this macro invocation
|
= note: this error originates in the macro `wrap` (in Nightly builds, run with -Z macro-backtrace for more info)
22 changes: 22 additions & 0 deletions ui-tests/tests/ui/bad_string_from_macro_rules_empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2026 Oxide Computer Company

// An empty macro_rules substitution (such as an empty `vis`) must be a
// missing-value error, not a panic.

use testlib::annotation;

macro_rules! wrap {
($v:vis ,) => {
#[annotation {
string = $v,
options = OptionA,
unit = (),
tup = (1, 2.0),
}]
fn test() {}
};
}

wrap!(,);

fn main() {}
10 changes: 10 additions & 0 deletions ui-tests/tests/ui/bad_string_from_macro_rules_empty.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: expected a string, but found `,`
--> tests/ui/bad_string_from_macro_rules_empty.rs:11:24
|
11 | string = $v,
| ^
...
20 | wrap!(,);
| -------- in this macro invocation
|
= note: this error originates in the macro `wrap` (in Nightly builds, run with -Z macro-backtrace for more info)
2 changes: 1 addition & 1 deletion ui-tests/tests/ui/bad_string_from_macro_rules_path.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: expected a string, but found `foo::bar`
error: expected only a string, but found `foo::bar`
--> tests/ui/bad_string_from_macro_rules_path.rs:20:7
|
20 | wrap!(foo::bar);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2026 Oxide Computer Company

// An empty macro_rules substitution into a TokenStreamWrapper must produce a
// missing-value error.

use testlib::tokens;

macro_rules! wrap {
($v:vis ,) => {
#[tokens {
tokens = $v,
}]
fn test() {}
};
}

wrap!(,);

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: expected a value, but found `,`
--> tests/ui/bad_token_stream_wrapper_from_macro_rules_empty.rs:11:24
|
11 | tokens = $v,
| ^
...
17 | wrap!(,);
| -------- in this macro invocation
|
= note: this error originates in the macro `wrap` (in Nightly builds, run with -Z macro-backtrace for more info)
24 changes: 24 additions & 0 deletions ui-tests/tests/ui/parse_wrapper_from_macro_rules_empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2026 Oxide Computer Company

// Empty macro_rules substitutions around a ParseWrapper value must be skipped.
// (The error produced must be for the later `maybe_string` field.)

use testlib::annotation;

macro_rules! wrap {
($v:vis ,) => {
#[annotation {
string = "test",
options = OptionA,
unit = (),
tup = (1, 2.0),
bool_expr = $v true $v,
maybe_string = 1,
}]
fn test() {}
};
}

wrap!(,);

fn main() {}
10 changes: 10 additions & 0 deletions ui-tests/tests/ui/parse_wrapper_from_macro_rules_empty.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: expected a string, but found `1`
--> tests/ui/parse_wrapper_from_macro_rules_empty.rs:16:28
|
16 | maybe_string = 1,
| ^
...
22 | wrap!(,);
| -------- in this macro invocation
|
= note: this error originates in the macro `wrap` (in Nightly builds, run with -Z macro-backtrace for more info)
23 changes: 23 additions & 0 deletions ui-tests/tests/ui/string_from_macro_rules.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2026 Oxide Computer Company

// With macro_rules substitutions, rustc will wrap the substitutions inside a
// `Delimiter::None` group. Ensure that such groups are accepted. (In this
// test, the error produced must be for the later `unit` field.)

use testlib::annotation;

macro_rules! wrap {
($s:expr) => {
#[annotation {
string = $s,
options = OptionA,
unit = 1,
tup = (1, 2.0),
}]
fn test() {}
};
}

wrap!(foo);

fn main() {}
10 changes: 10 additions & 0 deletions ui-tests/tests/ui/string_from_macro_rules.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: expected a unit, but found `1`
--> tests/ui/string_from_macro_rules.rs:14:20
|
14 | unit = 1,
| ^
...
21 | wrap!(foo);
| ---------- in this macro invocation
|
= note: this error originates in the macro `wrap` (in Nightly builds, run with -Z macro-backtrace for more info)
23 changes: 23 additions & 0 deletions ui-tests/tests/ui/string_from_macro_rules_empty_prefix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2026 Oxide Computer Company

// An empty macro_rules substitution before a value must be skipped. (The error
// produced must be for the later `maybe_string` field.)

use testlib::annotation;

macro_rules! wrap {
($v:vis ,) => {
#[annotation {
string = $v foo,
options = OptionA,
unit = (),
tup = (1, 2.0),
maybe_string = 1,
}]
fn test() {}
};
}

wrap!(,);

fn main() {}
10 changes: 10 additions & 0 deletions ui-tests/tests/ui/string_from_macro_rules_empty_prefix.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: expected a string, but found `1`
--> tests/ui/string_from_macro_rules_empty_prefix.rs:15:28
|
15 | maybe_string = 1,
| ^
...
21 | wrap!(,);
| -------- in this macro invocation
|
= note: this error originates in the macro `wrap` (in Nightly builds, run with -Z macro-backtrace for more info)
23 changes: 23 additions & 0 deletions ui-tests/tests/ui/string_from_macro_rules_empty_suffix.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2026 Oxide Computer Company

// An macro_rules substitution after a value must be skipped. (The error
// produced must be for the later `maybe_string` field.)

use testlib::annotation;

macro_rules! wrap {
($v:vis ,) => {
#[annotation {
string = foo $v,
options = OptionA,
unit = (),
tup = (1, 2.0),
maybe_string = 1,
}]
fn test() {}
};
}

wrap!(,);

fn main() {}
10 changes: 10 additions & 0 deletions ui-tests/tests/ui/string_from_macro_rules_empty_suffix.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: expected a string, but found `1`
--> tests/ui/string_from_macro_rules_empty_suffix.rs:15:28
|
15 | maybe_string = 1,
| ^
...
21 | wrap!(,);
| -------- in this macro invocation
|
= note: this error originates in the macro `wrap` (in Nightly builds, run with -Z macro-backtrace for more info)
26 changes: 26 additions & 0 deletions ui-tests/tests/ui/values_from_macro_rules.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2026 Oxide Computer Company

// Test that macro_rules substitutions are accepted for every value kind. (The
// error must be for the later `maybe_string` field.)

use testlib::annotation;

macro_rules! wrap {
($o:expr, $u:expr, $t:expr, $m:expr, $n:expr, $g:expr) => {
#[annotation {
string = "test",
options = $o,
unit = $u,
tup = $t,
many = $m,
nested = { squeaker = "x", eyas = $n, gosling = 1.0 },
painted = { color = { red = true, green = $g, blue = false } },
maybe_string = 1,
}]
fn test() {}
};
}

wrap!(OptionA, (), (1, 2.0), ["a", b], 7, false);

fn main() {}
10 changes: 10 additions & 0 deletions ui-tests/tests/ui/values_from_macro_rules.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
error: expected a string, but found `1`
--> tests/ui/values_from_macro_rules.rs:18:28
|
18 | maybe_string = 1,
| ^
...
24 | wrap!(OptionA, (), (1, 2.0), ["a", b], 7, false);
| ------------------------------------------------ in this macro invocation
|
= note: this error originates in the macro `wrap` (in Nightly builds, run with -Z macro-backtrace for more info)