qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/4] rust: use attrs crate to parse #[property]
@ 2025-07-17  6:27 Paolo Bonzini
  2025-07-17  6:27 ` [PATCH 1/4] subprojects: update proc-macro2 and syn Paolo Bonzini
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Paolo Bonzini @ 2025-07-17  6:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-rust, manos.pitsidianakis

This needs a bit of preparation, but it simplifies the handwritten parsing
code down to approximately 10 lines, and slightly improves the error
messages too.  All the scaffolding will be shared by future uses of
procedural macros.

Thanks to the author of the attrs crate, Aatif Syed, for accepting to lower
his crate's minimum supported Rust version to 1.83.

Paolo

Paolo Bonzini (4):
  subprojects: update proc-macro2 and syn
  subprojects: add attrs crate
  rust: qemu-api-macros: support matching more than one error
  rust: qemu-api-macros: switch #[property] parsing to use combinators

 rust/Cargo.lock                               | 19 ++++-
 rust/meson.build                              |  2 +
 rust/qemu-api-macros/Cargo.toml               |  1 +
 rust/qemu-api-macros/meson.build              |  1 +
 rust/qemu-api-macros/src/lib.rs               | 84 +++++++------------
 rust/qemu-api-macros/src/tests.rs             | 14 ++--
 scripts/archive-source.sh                     |  2 +-
 scripts/make-release                          |  2 +-
 subprojects/.gitignore                        |  5 +-
 subprojects/attrs-0.2-rs.wrap                 |  7 ++
 .../packagefiles/attrs-0.2-rs/meson.build     | 32 +++++++
 .../packagefiles/proc-macro2-1-rs/meson.build |  2 +-
 subprojects/packagefiles/syn-2-rs/meson.build |  2 +-
 subprojects/proc-macro2-1-rs.wrap             |  8 +-
 subprojects/syn-2-rs.wrap                     |  8 +-
 15 files changed, 111 insertions(+), 78 deletions(-)
 create mode 100644 subprojects/attrs-0.2-rs.wrap
 create mode 100644 subprojects/packagefiles/attrs-0.2-rs/meson.build

-- 
2.50.1



^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/4] subprojects: update proc-macro2 and syn
  2025-07-17  6:27 [RFC PATCH 0/4] rust: use attrs crate to parse #[property] Paolo Bonzini
@ 2025-07-17  6:27 ` Paolo Bonzini
  2025-07-17  6:27 ` [PATCH 2/4] subprojects: add attrs crate Paolo Bonzini
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Paolo Bonzini @ 2025-07-17  6:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-rust, manos.pitsidianakis

Update to a version that is accepted by the attrs crate.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 rust/Cargo.lock                                       | 8 ++++----
 subprojects/.gitignore                                | 4 ++--
 subprojects/packagefiles/proc-macro2-1-rs/meson.build | 2 +-
 subprojects/packagefiles/syn-2-rs/meson.build         | 2 +-
 subprojects/proc-macro2-1-rs.wrap                     | 8 ++++----
 subprojects/syn-2-rs.wrap                             | 8 ++++----
 6 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index b785c718f31..4baf6ba663c 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -118,9 +118,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.84"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
 dependencies = [
  "unicode-ident",
 ]
@@ -155,9 +155,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.66"
+version = "2.0.104"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
 dependencies = [
  "proc-macro2",
  "quote",
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
index f4281934ce1..9d579f72d12 100644
--- a/subprojects/.gitignore
+++ b/subprojects/.gitignore
@@ -16,7 +16,7 @@
 /libc-0.2.162
 /proc-macro-error-1.0.4
 /proc-macro-error-attr-1.0.4
-/proc-macro2-1.0.84
+/proc-macro2-1.0.95
 /quote-1.0.36
-/syn-2.0.66
+/syn-2.0.104
 /unicode-ident-1.0.12
diff --git a/subprojects/packagefiles/proc-macro2-1-rs/meson.build b/subprojects/packagefiles/proc-macro2-1-rs/meson.build
index 5759df3ecc9..ba7de070292 100644
--- a/subprojects/packagefiles/proc-macro2-1-rs/meson.build
+++ b/subprojects/packagefiles/proc-macro2-1-rs/meson.build
@@ -1,6 +1,6 @@
 project('proc-macro2-1-rs', 'rust',
   meson_version: '>=1.5.0',
-  version: '1.0.84',
+  version: '1.0.95',
   license: 'MIT OR Apache-2.0',
   default_options: [])
 
diff --git a/subprojects/packagefiles/syn-2-rs/meson.build b/subprojects/packagefiles/syn-2-rs/meson.build
index a0094174084..3e6dc318a9c 100644
--- a/subprojects/packagefiles/syn-2-rs/meson.build
+++ b/subprojects/packagefiles/syn-2-rs/meson.build
@@ -1,6 +1,6 @@
 project('syn-2-rs', 'rust',
   meson_version: '>=1.5.0',
-  version: '2.0.66',
+  version: '2.0.104',
   license: 'MIT OR Apache-2.0',
   default_options: [])
 
diff --git a/subprojects/proc-macro2-1-rs.wrap b/subprojects/proc-macro2-1-rs.wrap
index 6c9369f0df3..0f06cd8e111 100644
--- a/subprojects/proc-macro2-1-rs.wrap
+++ b/subprojects/proc-macro2-1-rs.wrap
@@ -1,8 +1,8 @@
 [wrap-file]
-directory = proc-macro2-1.0.84
-source_url = https://crates.io/api/v1/crates/proc-macro2/1.0.84/download
-source_filename = proc-macro2-1.0.84.0.tar.gz
-source_hash = ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6
+directory = proc-macro2-1.0.95
+source_url = https://crates.io/api/v1/crates/proc-macro2/1.0.95/download
+source_filename = proc-macro2-1.0.95.0.tar.gz
+source_hash = 02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778
 #method = cargo
 patch_directory = proc-macro2-1-rs
 
diff --git a/subprojects/syn-2-rs.wrap b/subprojects/syn-2-rs.wrap
index d79cf750fb4..1e5e9d9fb6e 100644
--- a/subprojects/syn-2-rs.wrap
+++ b/subprojects/syn-2-rs.wrap
@@ -1,8 +1,8 @@
 [wrap-file]
-directory = syn-2.0.66
-source_url = https://crates.io/api/v1/crates/syn/2.0.66/download
-source_filename = syn-2.0.66.0.tar.gz
-source_hash = c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5
+directory = syn-2.0.104
+source_url = https://crates.io/api/v1/crates/syn/2.0.104/download
+source_filename = syn-2.0.104.0.tar.gz
+source_hash = 17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40
 #method = cargo
 patch_directory = syn-2-rs
 
-- 
2.50.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/4] subprojects: add attrs crate
  2025-07-17  6:27 [RFC PATCH 0/4] rust: use attrs crate to parse #[property] Paolo Bonzini
  2025-07-17  6:27 ` [PATCH 1/4] subprojects: update proc-macro2 and syn Paolo Bonzini
@ 2025-07-17  6:27 ` Paolo Bonzini
  2025-07-17  6:27 ` [PATCH 3/4] rust: qemu-api-macros: support matching more than one error Paolo Bonzini
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Paolo Bonzini @ 2025-07-17  6:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-rust, manos.pitsidianakis

The attrs crate is a simple combinator-based parser for Rust attributes.
It will be used instead of a handwritten parser.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 rust/Cargo.lock                               | 11 +++++++
 rust/meson.build                              |  2 ++
 rust/qemu-api-macros/Cargo.toml               |  1 +
 rust/qemu-api-macros/meson.build              |  1 +
 scripts/archive-source.sh                     |  2 +-
 scripts/make-release                          |  2 +-
 subprojects/.gitignore                        |  1 +
 subprojects/attrs-0.2-rs.wrap                 |  7 ++++
 .../packagefiles/attrs-0.2-rs/meson.build     | 32 +++++++++++++++++++
 9 files changed, 57 insertions(+), 2 deletions(-)
 create mode 100644 subprojects/attrs-0.2-rs.wrap
 create mode 100644 subprojects/packagefiles/attrs-0.2-rs/meson.build

diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index 4baf6ba663c..570ba5b82d3 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -14,6 +14,16 @@ version = "1.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d"
 
+[[package]]
+name = "attrs"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a207d40f43de65285f3de0509bb6cb16bc46098864fce957122bbacce327e5f"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
 [[package]]
 name = "bilge"
 version = "0.2.0"
@@ -139,6 +149,7 @@ dependencies = [
 name = "qemu_api_macros"
 version = "0.1.0"
 dependencies = [
+ "attrs",
  "proc-macro2",
  "quote",
  "syn",
diff --git a/rust/meson.build b/rust/meson.build
index 331f11b7e72..21df23c1f9e 100644
--- a/rust/meson.build
+++ b/rust/meson.build
@@ -13,10 +13,12 @@ libc_rs = dependency('libc-0.2-rs')
 subproject('proc-macro2-1-rs', required: true)
 subproject('quote-1-rs', required: true)
 subproject('syn-2-rs', required: true)
+subproject('attrs-0.2-rs', required: true)
 
 quote_rs_native = dependency('quote-1-rs', native: true)
 syn_rs_native = dependency('syn-2-rs', native: true)
 proc_macro2_rs_native = dependency('proc-macro2-1-rs', native: true)
+attrs_rs_native = dependency('attrs-0.2-rs', native: true)
 
 qemuutil_rs = qemuutil.partial_dependency(link_args: true, links: true)
 
diff --git a/rust/qemu-api-macros/Cargo.toml b/rust/qemu-api-macros/Cargo.toml
index 0cd40c8e168..99f7a425fcc 100644
--- a/rust/qemu-api-macros/Cargo.toml
+++ b/rust/qemu-api-macros/Cargo.toml
@@ -16,6 +16,7 @@ rust-version.workspace = true
 proc-macro = true
 
 [dependencies]
+attrs = "0.2.9"
 proc-macro2 = "1"
 quote = "1"
 syn = { version = "2", features = ["extra-traits"] }
diff --git a/rust/qemu-api-macros/meson.build b/rust/qemu-api-macros/meson.build
index 2152bcb99b3..12d02b20c20 100644
--- a/rust/qemu-api-macros/meson.build
+++ b/rust/qemu-api-macros/meson.build
@@ -8,6 +8,7 @@ _qemu_api_macros_rs = rust.proc_macro(
     '--cfg', 'feature="proc-macro"',
   ],
   dependencies: [
+    attrs_rs_native,
     proc_macro2_rs_native,
     quote_rs_native,
     syn_rs_native,
diff --git a/scripts/archive-source.sh b/scripts/archive-source.sh
index 035828c532e..476a996a70d 100755
--- a/scripts/archive-source.sh
+++ b/scripts/archive-source.sh
@@ -27,7 +27,7 @@ sub_file="${sub_tdir}/submodule.tar"
 # in their checkout, because the build environment is completely
 # different to the host OS.
 subprojects="keycodemapdb libvfio-user berkeley-softfloat-3
-  berkeley-testfloat-3 anyhow-1-rs arbitrary-int-1-rs bilge-0.2-rs
+  berkeley-testfloat-3 anyhow-1-rs arbitrary-int-1-rs attrs-0.2-rs bilge-0.2-rs
   bilge-impl-0.2-rs either-1-rs foreign-0.3-rs itertools-0.11-rs
   libc-0.2-rs proc-macro2-1-rs
   proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
diff --git a/scripts/make-release b/scripts/make-release
index 4509a9fabf5..00a91fb95f4 100755
--- a/scripts/make-release
+++ b/scripts/make-release
@@ -40,7 +40,7 @@ fi
 
 # Only include wraps that are invoked with subproject()
 SUBPROJECTS="libvfio-user keycodemapdb berkeley-softfloat-3
-  berkeley-testfloat-3 anyhow-1-rs arbitrary-int-1-rs bilge-0.2-rs
+  berkeley-testfloat-3 anyhow-1-rs arbitrary-int-1-rs attrs-0.2-rs bilge-0.2-rs
   bilge-impl-0.2-rs either-1-rs foreign-0.3-rs itertools-0.11-rs
   libc-0.2-rs proc-macro2-1-rs
   proc-macro-error-1-rs proc-macro-error-attr-1-rs quote-1-rs
diff --git a/subprojects/.gitignore b/subprojects/.gitignore
index 9d579f72d12..1ffd9513671 100644
--- a/subprojects/.gitignore
+++ b/subprojects/.gitignore
@@ -8,6 +8,7 @@
 /slirp
 /anyhow-1.0.98
 /arbitrary-int-1.2.7
+/attrs-0.2.9
 /bilge-0.2.0
 /bilge-impl-0.2.0
 /either-1.12.0
diff --git a/subprojects/attrs-0.2-rs.wrap b/subprojects/attrs-0.2-rs.wrap
new file mode 100644
index 00000000000..cd43c91d63e
--- /dev/null
+++ b/subprojects/attrs-0.2-rs.wrap
@@ -0,0 +1,7 @@
+[wrap-file]
+directory = attrs-0.2.9
+source_url = https://crates.io/api/v1/crates/attrs/0.2.9/download
+source_filename = attrs-0.2.9.tar.gz
+source_hash = 2a207d40f43de65285f3de0509bb6cb16bc46098864fce957122bbacce327e5f
+#method = cargo
+patch_directory = attrs-0.2-rs
diff --git a/subprojects/packagefiles/attrs-0.2-rs/meson.build b/subprojects/packagefiles/attrs-0.2-rs/meson.build
new file mode 100644
index 00000000000..fc6f269dcbf
--- /dev/null
+++ b/subprojects/packagefiles/attrs-0.2-rs/meson.build
@@ -0,0 +1,32 @@
+project('attrs-0.2-rs', 'rust',
+  meson_version: '>=1.5.0',
+  version: '0.2.9',
+  license: 'MIT OR Apache-2.0',
+  default_options: [])
+
+subproject('attrs-0.2-rs', required: true)
+
+proc_macro2_dep = dependency('proc-macro2-1-rs', native: true)
+syn_dep = dependency('syn-2-rs', native: true)
+
+_attrs_rs = static_library(
+  'attrs',
+  files('src/lib.rs'),
+  gnu_symbol_visibility: 'hidden',
+  override_options: ['rust_std=2021', 'build.rust_std=2021'],
+  rust_abi: 'rust',
+  rust_args: [
+    '--cap-lints', 'allow',
+  ],
+  dependencies: [
+    proc_macro2_dep,
+    syn_dep,
+  ],
+  native: true,
+)
+
+attrs_dep = declare_dependency(
+  link_with: _attrs_rs,
+)
+
+meson.override_dependency('attrs-0.2-rs', attrs_dep, native: true)
-- 
2.50.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 3/4] rust: qemu-api-macros: support matching more than one error
  2025-07-17  6:27 [RFC PATCH 0/4] rust: use attrs crate to parse #[property] Paolo Bonzini
  2025-07-17  6:27 ` [PATCH 1/4] subprojects: update proc-macro2 and syn Paolo Bonzini
  2025-07-17  6:27 ` [PATCH 2/4] subprojects: add attrs crate Paolo Bonzini
@ 2025-07-17  6:27 ` Paolo Bonzini
  2025-07-17  6:27 ` [PATCH 4/4] qemu-api-macros: switch #[property] parsing to use combinators Paolo Bonzini
  2025-07-17  9:18 ` [RFC PATCH 0/4] rust: use attrs crate to parse #[property] Manos Pitsidianakis
  4 siblings, 0 replies; 7+ messages in thread
From: Paolo Bonzini @ 2025-07-17  6:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-rust, manos.pitsidianakis

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 rust/qemu-api-macros/src/tests.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/rust/qemu-api-macros/src/tests.rs b/rust/qemu-api-macros/src/tests.rs
index 4fbff97bffb..0e5a5728908 100644
--- a/rust/qemu-api-macros/src/tests.rs
+++ b/rust/qemu-api-macros/src/tests.rs
@@ -7,9 +7,9 @@
 use super::*;
 
 macro_rules! derive_compile_fail {
-    ($derive_fn:ident, $input:expr, $error_msg:expr) => {{
+    ($derive_fn:ident, $input:expr, $($error_msg:expr),+ $(,)?) => {{
         let input: proc_macro2::TokenStream = $input;
-        let error_msg: &str = $error_msg;
+        let error_msg = &[$( quote! { ::core::compile_error! { $error_msg } } ),*];
         let derive_fn: fn(input: syn::DeriveInput) -> Result<proc_macro2::TokenStream, syn::Error> =
             $derive_fn;
 
@@ -18,7 +18,7 @@ macro_rules! derive_compile_fail {
         let err = result.unwrap_err().into_compile_error();
         assert_eq!(
             err.to_string(),
-            quote! { ::core::compile_error! { #error_msg } }.to_string()
+            quote! { #(#error_msg)* }.to_string()
         );
     }};
 }
-- 
2.50.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 4/4] qemu-api-macros: switch #[property] parsing to use combinators
  2025-07-17  6:27 [RFC PATCH 0/4] rust: use attrs crate to parse #[property] Paolo Bonzini
                   ` (2 preceding siblings ...)
  2025-07-17  6:27 ` [PATCH 3/4] rust: qemu-api-macros: support matching more than one error Paolo Bonzini
@ 2025-07-17  6:27 ` Paolo Bonzini
  2025-07-17  9:18 ` [RFC PATCH 0/4] rust: use attrs crate to parse #[property] Manos Pitsidianakis
  4 siblings, 0 replies; 7+ messages in thread
From: Paolo Bonzini @ 2025-07-17  6:27 UTC (permalink / raw)
  To: qemu-devel; +Cc: qemu-rust, manos.pitsidianakis

attrs is a simple crate that provides parser combinators for
attribute arguments.  Use it instead of a handwritten parser,
and adjust tests.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 rust/qemu-api-macros/src/lib.rs   | 84 +++++++++++--------------------
 rust/qemu-api-macros/src/tests.rs |  8 +--
 2 files changed, 35 insertions(+), 57 deletions(-)

diff --git a/rust/qemu-api-macros/src/lib.rs b/rust/qemu-api-macros/src/lib.rs
index a0a8d758bcc..b3d44da9300 100644
--- a/rust/qemu-api-macros/src/lib.rs
+++ b/rust/qemu-api-macros/src/lib.rs
@@ -3,11 +3,11 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 
 use proc_macro::TokenStream;
-use quote::{quote, quote_spanned, ToTokens};
+use quote::{quote, quote_spanned};
 use syn::{
-    parse::Parse, parse_macro_input, parse_quote, punctuated::Punctuated, spanned::Spanned,
-    token::Comma, Data, DeriveInput, Error, Field, Fields, FieldsUnnamed, Ident, Meta, Path, Token,
-    Variant,
+    parse::Parse, parse::ParseStream, parse_macro_input, parse_quote, punctuated::Punctuated,
+    spanned::Spanned, token::Comma, Attribute, Data, DeriveInput, Error, Field, Fields, FieldsUnnamed,
+    Ident, Meta, Path, Token, Variant,
 };
 mod bits;
 use bits::BitsConstInternal;
@@ -153,61 +153,37 @@ enum DevicePropertyName {
     Str(syn::LitStr),
 }
 
-#[derive(Debug)]
+impl Parse for DevicePropertyName {
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        let lo = input.lookahead1();
+        if lo.peek(syn::LitStr) {
+            Ok(Self::Str(input.parse()?))
+        } else if lo.peek(syn::LitCStr) {
+            Ok(Self::CStr(input.parse()?))
+        } else {
+            Err(lo.error())
+        }
+    }
+}
+
+#[derive(Default, Debug)]
 struct DeviceProperty {
     rename: Option<DevicePropertyName>,
     defval: Option<syn::Expr>,
 }
 
-impl Parse for DeviceProperty {
-    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
-        let _: syn::Token![#] = input.parse()?;
-        let bracketed;
-        _ = syn::bracketed!(bracketed in input);
-        let attribute = bracketed.parse::<syn::Ident>()?;
-        debug_assert_eq!(&attribute.to_string(), "property");
-        let mut retval = Self {
-            rename: None,
-            defval: None,
-        };
-        let content;
-        _ = syn::parenthesized!(content in bracketed);
-        while !content.is_empty() {
-            let value: syn::Ident = content.parse()?;
-            if value == "rename" {
-                let _: syn::Token![=] = content.parse()?;
-                if retval.rename.is_some() {
-                    return Err(syn::Error::new(
-                        value.span(),
-                        "`rename` can only be used at most once",
-                    ));
-                }
-                if content.peek(syn::LitStr) {
-                    retval.rename = Some(DevicePropertyName::Str(content.parse::<syn::LitStr>()?));
-                } else {
-                    retval.rename =
-                        Some(DevicePropertyName::CStr(content.parse::<syn::LitCStr>()?));
-                }
-            } else if value == "default" {
-                let _: syn::Token![=] = content.parse()?;
-                if retval.defval.is_some() {
-                    return Err(syn::Error::new(
-                        value.span(),
-                        "`default` can only be used at most once",
-                    ));
-                }
-                retval.defval = Some(content.parse()?);
-            } else {
-                return Err(syn::Error::new(
-                    value.span(),
-                    format!("unrecognized field `{value}`"),
-                ));
-            }
+impl DeviceProperty {
+    fn parse_from(&mut self, a: &Attribute) -> syn::Result<()> {
+        use attrs::{set, with, Attrs};
+        let mut parser = Attrs::new();
+        parser.once("rename", with::eq(set::parse(&mut self.rename)));
+        parser.once("default", with::eq(set::parse(&mut self.defval)));
+        a.parse_args_with(&mut parser)
+    }
 
-            if !content.is_empty() {
-                let _: syn::Token![,] = content.parse()?;
-            }
-        }
+    fn parse(a: &Attribute) -> syn::Result<Self> {
+        let mut retval = Self::default();
+        retval.parse_from(a)?;
         Ok(retval)
     }
 }
@@ -229,7 +205,7 @@ fn derive_device_or_error(input: DeriveInput) -> Result<proc_macro2::TokenStream
             f.attrs
                 .iter()
                 .filter(|a| a.path().is_ident("property"))
-                .map(|a| Ok((f.clone(), syn::parse2(a.to_token_stream())?)))
+                .map(|a| Ok((f.clone(), DeviceProperty::parse(&a)?)))
         })
         .collect::<Result<Vec<_>, Error>>()?;
     let name = &input.ident;
diff --git a/rust/qemu-api-macros/src/tests.rs b/rust/qemu-api-macros/src/tests.rs
index 0e5a5728908..3c056652666 100644
--- a/rust/qemu-api-macros/src/tests.rs
+++ b/rust/qemu-api-macros/src/tests.rs
@@ -60,7 +60,7 @@ struct DummyState {
                 migrate_clock: bool,
             }
         },
-        "unrecognized field `defalt`"
+        "Expected one of `default` or `rename`"
     );
     // Check that repeated attributes are not allowed:
     derive_compile_fail!(
@@ -73,7 +73,8 @@ struct DummyState {
                 migrate_clock: bool,
             }
         },
-        "`rename` can only be used at most once"
+        "Duplicate argument",
+        "Already used here",
     );
     derive_compile_fail!(
         derive_device_or_error,
@@ -85,7 +86,8 @@ struct DummyState {
                 migrate_clock: bool,
             }
         },
-        "`default` can only be used at most once"
+        "Duplicate argument",
+        "Already used here",
     );
     // Check that the field name is preserved when `rename` isn't used:
     derive_compile!(
-- 
2.50.1



^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH 0/4] rust: use attrs crate to parse #[property]
  2025-07-17  6:27 [RFC PATCH 0/4] rust: use attrs crate to parse #[property] Paolo Bonzini
                   ` (3 preceding siblings ...)
  2025-07-17  6:27 ` [PATCH 4/4] qemu-api-macros: switch #[property] parsing to use combinators Paolo Bonzini
@ 2025-07-17  9:18 ` Manos Pitsidianakis
  2025-07-17 13:17   ` Paolo Bonzini
  4 siblings, 1 reply; 7+ messages in thread
From: Manos Pitsidianakis @ 2025-07-17  9:18 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel, qemu-rust

On Thu, Jul 17, 2025 at 9:27 AM Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> This needs a bit of preparation, but it simplifies the handwritten parsing
> code down to approximately 10 lines, and slightly improves the error
> messages too.  All the scaffolding will be shared by future uses of
> procedural macros.
>
> Thanks to the author of the attrs crate, Aatif Syed, for accepting to lower
> his crate's minimum supported Rust version to 1.83.
>
> Paolo
>
> Paolo Bonzini (4):
>   subprojects: update proc-macro2 and syn
>   subprojects: add attrs crate
>   rust: qemu-api-macros: support matching more than one error
>   rust: qemu-api-macros: switch #[property] parsing to use combinators
>
>  rust/Cargo.lock                               | 19 ++++-
>  rust/meson.build                              |  2 +
>  rust/qemu-api-macros/Cargo.toml               |  1 +
>  rust/qemu-api-macros/meson.build              |  1 +
>  rust/qemu-api-macros/src/lib.rs               | 84 +++++++------------
>  rust/qemu-api-macros/src/tests.rs             | 14 ++--
>  scripts/archive-source.sh                     |  2 +-
>  scripts/make-release                          |  2 +-
>  subprojects/.gitignore                        |  5 +-
>  subprojects/attrs-0.2-rs.wrap                 |  7 ++
>  .../packagefiles/attrs-0.2-rs/meson.build     | 32 +++++++
>  .../packagefiles/proc-macro2-1-rs/meson.build |  2 +-
>  subprojects/packagefiles/syn-2-rs/meson.build |  2 +-
>  subprojects/proc-macro2-1-rs.wrap             |  8 +-
>  subprojects/syn-2-rs.wrap                     |  8 +-
>  15 files changed, 111 insertions(+), 78 deletions(-)
>  create mode 100644 subprojects/attrs-0.2-rs.wrap
>  create mode 100644 subprojects/packagefiles/attrs-0.2-rs/meson.build
>
> --
> 2.50.1
>

Looks OK to me but are we sure it's necessary? This dependency is just
a syn::parse wrapper under the hood. Even serde's derive macros use
syn directly: https://github.com/serde-rs/serde/blob/babafa54d283fb087fa94f50a2cf82fa9e582a7c/serde_derive/src/internals/attr.rs#L276

I'm not against dependencies mind you, but this replaces just a few
lines of code.

-- 
Manos Pitsidianakis
Emulation and Virtualization Engineer at Linaro Ltd


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [RFC PATCH 0/4] rust: use attrs crate to parse #[property]
  2025-07-17  9:18 ` [RFC PATCH 0/4] rust: use attrs crate to parse #[property] Manos Pitsidianakis
@ 2025-07-17 13:17   ` Paolo Bonzini
  0 siblings, 0 replies; 7+ messages in thread
From: Paolo Bonzini @ 2025-07-17 13:17 UTC (permalink / raw)
  To: Manos Pitsidianakis; +Cc: qemu-devel, qemu-rust

[-- Attachment #1: Type: text/plain, Size: 1044 bytes --]

Il gio 17 lug 2025, 11:18 Manos Pitsidianakis <
manos.pitsidianakis@linaro.org> ha scritto:

> Looks OK to me but are we sure it's necessary? This dependency is just
> a syn::parse wrapper under the hood. Even serde's derive macros use
> syn directly:
> https://github.com/serde-rs/serde/blob/babafa54d283fb087fa94f50a2cf82fa9e582a7c/serde_derive/src/internals/attr.rs#L276
>
> I'm not against dependencies mind you, but this replaces just a few
> lines of code.
>

It depends on how many copies of the procedural macros parsing code we have
(hence RFC).

If you introduced a #[device] or #[object] attribute, for example, it
probably would make a lot more sense than for #[property] only. Besides the
shorter code it would also provide more consistent error messages across
the attributes.

For just one macro, what you have now is fine. I did this series mostly to
have it ready and check that attrs respects the same MSRV as QEMU (it
didn't :)).

Paolo



> --
> Manos Pitsidianakis
> Emulation and Virtualization Engineer at Linaro Ltd
>
>

[-- Attachment #2: Type: text/html, Size: 2042 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-07-17 15:27 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-17  6:27 [RFC PATCH 0/4] rust: use attrs crate to parse #[property] Paolo Bonzini
2025-07-17  6:27 ` [PATCH 1/4] subprojects: update proc-macro2 and syn Paolo Bonzini
2025-07-17  6:27 ` [PATCH 2/4] subprojects: add attrs crate Paolo Bonzini
2025-07-17  6:27 ` [PATCH 3/4] rust: qemu-api-macros: support matching more than one error Paolo Bonzini
2025-07-17  6:27 ` [PATCH 4/4] qemu-api-macros: switch #[property] parsing to use combinators Paolo Bonzini
2025-07-17  9:18 ` [RFC PATCH 0/4] rust: use attrs crate to parse #[property] Manos Pitsidianakis
2025-07-17 13:17   ` Paolo Bonzini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).