Browse Source

Replace proc-macro-error with proc-macro2-diagnostics

proc-macro-error is unmaintained.
Tamir Duberstein 4 months ago
parent
commit
5a43bedc01

+ 1 - 1
Cargo.toml

@@ -81,8 +81,8 @@ nix = { version = "0.29.0", default-features = false }
 num_enum = { version = "0.7", default-features = false }
 object = { version = "0.36", default-features = false }
 once_cell = { version = "1.20.1", default-features = false }
-proc-macro-error = { version = "1.0", default-features = false }
 proc-macro2 = { version = "1", default-features = false }
+proc-macro2-diagnostics = { version = "0.10.1", default-features = false }
 public-api = { version = "0.42.0", default-features = false }
 quote = { version = "1", default-features = false }
 rand = { version = "0.8", default-features = false }

+ 1 - 1
aya-ebpf-macros/Cargo.toml

@@ -13,7 +13,7 @@ proc-macro = true
 
 [dependencies]
 proc-macro2 = { workspace = true }
-proc-macro-error = { workspace = true }
+proc-macro2-diagnostics = { workspace = true }
 quote = { workspace = true }
 syn = { workspace = true, default-features = true, features = ["full"] }
 

+ 16 - 11
aya-ebpf-macros/src/btf_tracepoint.rs

@@ -18,28 +18,33 @@ impl BtfTracePoint {
         let function = pop_string_arg(&mut args, "function");
         err_on_unknown_args(&args)?;
 
-        Ok(BtfTracePoint { item, function })
+        Ok(Self { item, function })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_name: Cow<'_, _> = if let Some(function) = &self.function {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item, function } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let section_name: Cow<'_, _> = if let Some(function) = function {
             format!("tp_btf/{}", function).into()
         } else {
             "tp_btf".into()
         };
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
+            #vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
                 let _ = #fn_name(::aya_ebpf::programs::BtfTracePointContext::new(ctx));
                 return 0;
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -60,7 +65,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote!(
             #[no_mangle]
             #[link_section = "tp_btf"]
@@ -87,7 +92,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote!(
             #[no_mangle]
             #[link_section = "tp_btf/some_func"]

+ 18 - 13
aya-ebpf-macros/src/cgroup_device.rs

@@ -1,34 +1,39 @@
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 pub(crate) struct CgroupDevice {
     item: ItemFn,
 }
 
 impl CgroupDevice {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         if !attrs.is_empty() {
-            abort!(attrs, "unexpected attribute")
+            return Err(attrs.span().error("unexpected attribute"));
         }
         let item = syn::parse2(item)?;
-        Ok(CgroupDevice { item })
+        Ok(Self { item })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = "cgroup/dev"]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_cgroup_dev_ctx) -> i32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_cgroup_dev_ctx) -> i32 {
                 return #fn_name(::aya_ebpf::programs::DeviceContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -49,7 +54,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/dev"]

+ 33 - 29
aya-ebpf-macros/src/cgroup_skb.rs

@@ -1,48 +1,52 @@
 use std::borrow::Cow;
 
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{Ident, ItemFn, Result};
+use syn::{Ident, ItemFn};
 
 pub(crate) struct CgroupSkb {
     item: ItemFn,
-    attach_type: Option<String>,
+    attach_type: Option<Ident>,
 }
 
 impl CgroupSkb {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<CgroupSkb> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         let item: ItemFn = syn::parse2(item)?;
-        let mut attach_type = None;
-        if !attrs.is_empty() {
+        let attach_type = if attrs.is_empty() {
+            None
+        } else {
             let ident: Ident = syn::parse2(attrs)?;
-            match ident.to_string().as_str() {
-                "ingress" | "egress" => (),
-                _ => abort!(ident, "invalid attach type"),
+            if ident != "ingress" && ident != "egress" {
+                return Err(ident.span().error("invalid attach type"));
             }
-            attach_type = Some(ident.to_string());
-        }
-        Ok(CgroupSkb { item, attach_type })
+            Some(ident)
+        };
+        Ok(Self { item, attach_type })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_name: Cow<'_, _> = if self.attach_type.is_some() {
-            format!("cgroup_skb/{}", self.attach_type.as_ref().unwrap()).into()
-        } else {
-            "cgroup/skb".into()
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item, attach_type } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let section_name: Cow<'_, _> = match attach_type {
+            Some(attach_type) => format!("cgroup_skb/{attach_type}").into(),
+            None => "cgroup/skb".into(),
         };
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::__sk_buff) -> i32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::__sk_buff) -> i32 {
                 return #fn_name(::aya_ebpf::programs::SkBuffContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -63,7 +67,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/skb"]
@@ -89,7 +93,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup_skb/egress"]
@@ -115,7 +119,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup_skb/ingress"]
@@ -141,7 +145,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup_skb/egress"]
@@ -167,7 +171,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup_skb/egress"]
@@ -193,7 +197,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup_skb/egress"]

+ 29 - 24
aya-ebpf-macros/src/cgroup_sock.rs

@@ -1,46 +1,51 @@
 use std::borrow::Cow;
 
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{Ident, ItemFn, Result};
+use syn::{spanned::Spanned as _, Ident, ItemFn};
 
 pub(crate) struct CgroupSock {
     item: ItemFn,
-    attach_type: String,
+    attach_type: Ident,
 }
 
 impl CgroupSock {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<CgroupSock> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         if attrs.is_empty() {
-            abort!(attrs, "missing attach type")
+            return Err(attrs.span().error("missing attach type"));
         }
         let item: ItemFn = syn::parse2(item)?;
         let attach_type: Ident = syn::parse2(attrs)?;
-        match attach_type.to_string().as_str() {
-            "post_bind4" | "post_bind6" | "sock_create" | "sock_release" => (),
-            _ => abort!(attach_type, "invalid attach type"),
+        if attach_type != "post_bind4"
+            && attach_type != "post_bind6"
+            && attach_type != "sock_create"
+            && attach_type != "sock_release"
+        {
+            return Err(attach_type.span().error("invalid attach type"));
         }
-        Ok(CgroupSock {
-            item,
-            attach_type: attach_type.to_string(),
-        })
+        Ok(Self { item, attach_type })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_name: Cow<'_, _> = format!("cgroup/{}", self.attach_type).into();
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item, attach_type } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let section_name: Cow<'_, _> = format!("cgroup/{attach_type}").into();
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sock) -> i32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sock) -> i32 {
                 return #fn_name(::aya_ebpf::programs::SockContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -61,7 +66,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/post_bind4"]
@@ -87,7 +92,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/post_bind6"]
@@ -112,7 +117,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/sock_create"]
@@ -137,7 +142,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/sock_release"]

+ 45 - 34
aya-ebpf-macros/src/cgroup_sock_addr.rs

@@ -1,48 +1,59 @@
 use std::borrow::Cow;
 
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{Ident, ItemFn, Result};
+use syn::{spanned::Spanned as _, Ident, ItemFn};
 
 pub(crate) struct CgroupSockAddr {
     item: ItemFn,
-    attach_type: String,
+    attach_type: Ident,
 }
 
 impl CgroupSockAddr {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         if attrs.is_empty() {
-            abort!(attrs, "missing attach type")
+            return Err(attrs.span().error("missing attach type"));
         }
         let item = syn::parse2(item)?;
         let attach_type: Ident = syn::parse2(attrs)?;
-        match attach_type.to_string().as_str() {
-            "connect4" | "connect6" | "bind4" | "bind6" | "getpeername4" | "getpeername6"
-            | "getsockname4" | "getsockname6" | "sendmsg4" | "sendmsg6" | "recvmsg4"
-            | "recvmsg6" => (),
-            _ => abort!(attach_type, "invalid attach type"),
+        if attach_type != "connect4"
+            && attach_type != "connect6"
+            && attach_type != "bind4"
+            && attach_type != "bind6"
+            && attach_type != "getpeername4"
+            && attach_type != "getpeername6"
+            && attach_type != "getsockname4"
+            && attach_type != "getsockname6"
+            && attach_type != "sendmsg4"
+            && attach_type != "sendmsg6"
+            && attach_type != "recvmsg4"
+            && attach_type != "recvmsg6"
+        {
+            return Err(attach_type.span().error("invalid attach type"));
         }
-        Ok(CgroupSockAddr {
-            item,
-            attach_type: attach_type.to_string(),
-        })
+        Ok(Self { item, attach_type })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_name: Cow<'_, _> = format!("cgroup/{}", self.attach_type).into();
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item, attach_type } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let section_name: Cow<'_, _> = format!("cgroup/{attach_type}").into();
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sock_addr) -> i32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sock_addr) -> i32 {
                 return #fn_name(::aya_ebpf::programs::SockAddrContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -63,7 +74,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/connect4"]
@@ -89,7 +100,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/connect6"]
@@ -115,7 +126,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/bind4"]
@@ -141,7 +152,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/bind6"]
@@ -167,7 +178,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/getpeername4"]
@@ -193,7 +204,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/getpeername6"]
@@ -219,7 +230,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/getsockname4"]
@@ -245,7 +256,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/getsockname6"]
@@ -271,7 +282,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/sendmsg4"]
@@ -297,7 +308,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/sendmsg6"]
@@ -323,7 +334,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/recvmsg4"]
@@ -349,7 +360,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/recvmsg6"]

+ 26 - 22
aya-ebpf-macros/src/cgroup_sockopt.rs

@@ -1,46 +1,50 @@
 use std::borrow::Cow;
 
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{Ident, ItemFn, Result};
+use syn::{spanned::Spanned as _, Ident, ItemFn};
 
 pub(crate) struct CgroupSockopt {
     item: ItemFn,
-    attach_type: String,
+    attach_type: Ident,
 }
 
 impl CgroupSockopt {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<CgroupSockopt> {
+    pub(crate) fn parse(
+        attrs: TokenStream,
+        item: TokenStream,
+    ) -> Result<CgroupSockopt, Diagnostic> {
         if attrs.is_empty() {
-            abort!(attrs, "expected attach type");
+            return Err(attrs.span().error("missing attach type"));
         }
         let item = syn::parse2(item)?;
         let attach_type: Ident = syn::parse2(attrs)?;
-        match attach_type.to_string().as_str() {
-            "getsockopt" | "setsockopt" => (),
-            _ => abort!(attach_type, "invalid attach type"),
+        if attach_type != "getsockopt" && attach_type != "setsockopt" {
+            return Err(attach_type.span().error("invalid attach type"));
         }
-        Ok(CgroupSockopt {
-            item,
-            attach_type: attach_type.to_string(),
-        })
+        Ok(Self { item, attach_type })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_name: Cow<'_, _> = format!("cgroup/{}", self.attach_type).into();
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item, attach_type } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let section_name: Cow<'_, _> = format!("cgroup/{attach_type}").into();
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sockopt) -> i32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sockopt) -> i32 {
                 return #fn_name(::aya_ebpf::programs::SockoptContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -61,7 +65,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote!(
             #[no_mangle]
             #[link_section = "cgroup/getsockopt"]
@@ -87,7 +91,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote!(
             #[no_mangle]
             #[link_section = "cgroup/setsockopt"]

+ 18 - 13
aya-ebpf-macros/src/cgroup_sysctl.rs

@@ -1,34 +1,39 @@
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 pub(crate) struct CgroupSysctl {
     item: ItemFn,
 }
 
 impl CgroupSysctl {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         if !attrs.is_empty() {
-            abort!(attrs, "unexpected attribute")
+            return Err(attrs.span().error("unexpected attribute"));
         }
         let item = syn::parse2(item)?;
-        Ok(CgroupSysctl { item })
+        Ok(Self { item })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = "cgroup/sysctl"]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sysctl) -> i32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sysctl) -> i32 {
                 return #fn_name(::aya_ebpf::programs::SysctlContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -49,7 +54,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "cgroup/sysctl"]

+ 23 - 14
aya-ebpf-macros/src/fentry.rs

@@ -13,39 +13,48 @@ pub(crate) struct FEntry {
 }
 
 impl FEntry {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<FEntry> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
         let item = syn::parse2(item)?;
         let mut args = syn::parse2(attrs)?;
         let function = pop_string_arg(&mut args, "function");
         let sleepable = pop_bool_arg(&mut args, "sleepable");
         err_on_unknown_args(&args)?;
-        Ok(FEntry {
+        Ok(Self {
             item,
             function,
             sleepable,
         })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_prefix = if self.sleepable { "fentry.s" } else { "fentry" };
-        let section_name: Cow<'_, _> = if let Some(function) = &self.function {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self {
+            item,
+            function,
+            sleepable,
+        } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let section_prefix = if *sleepable { "fentry.s" } else { "fentry" };
+        let section_name: Cow<'_, _> = if let Some(function) = function {
             format!("{}/{}", section_prefix, function).into()
         } else {
             section_prefix.into()
         };
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
+            #vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
                 let _ = #fn_name(::aya_ebpf::programs::FEntryContext::new(ctx));
                 return 0;
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -66,7 +75,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "fentry"]
@@ -95,7 +104,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "fentry/sys_clone"]
@@ -124,7 +133,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "fentry.s"]

+ 23 - 14
aya-ebpf-macros/src/fexit.rs

@@ -13,39 +13,48 @@ pub(crate) struct FExit {
 }
 
 impl FExit {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<FExit> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
         let item = syn::parse2(item)?;
         let mut args = syn::parse2(attrs)?;
         let function = pop_string_arg(&mut args, "function");
         let sleepable = pop_bool_arg(&mut args, "sleepable");
         err_on_unknown_args(&args)?;
-        Ok(FExit {
+        Ok(Self {
             item,
             function,
             sleepable,
         })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_prefix = if self.sleepable { "fexit.s" } else { "fexit" };
-        let section_name: Cow<'_, _> = if let Some(function) = &self.function {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self {
+            item,
+            function,
+            sleepable,
+        } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let section_prefix = if *sleepable { "fexit.s" } else { "fexit" };
+        let section_name: Cow<'_, _> = if let Some(function) = function {
             format!("{}/{}", section_prefix, function).into()
         } else {
             section_prefix.into()
         };
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
+            #vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
                 let _ = #fn_name(::aya_ebpf::programs::FExitContext::new(ctx));
                 return 0;
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -66,7 +75,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "fexit"]
@@ -95,7 +104,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "fexit/sys_clone"]
@@ -124,7 +133,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "fexit.s/sys_clone"]

+ 41 - 28
aya-ebpf-macros/src/kprobe.rs

@@ -1,8 +1,9 @@
 use std::borrow::Cow;
 
 use proc_macro2::TokenStream;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 use crate::args::{err_on_unknown_args, pop_string_arg};
 
@@ -31,14 +32,23 @@ pub(crate) struct KProbe {
 }
 
 impl KProbe {
-    pub(crate) fn parse(kind: KProbeKind, attrs: TokenStream, item: TokenStream) -> Result<KProbe> {
+    pub(crate) fn parse(
+        kind: KProbeKind,
+        attrs: TokenStream,
+        item: TokenStream,
+    ) -> Result<Self, Diagnostic> {
         let item = syn::parse2(item)?;
+        let span = attrs.span();
         let mut args = syn::parse2(attrs)?;
         let function = pop_string_arg(&mut args, "function");
-        let offset = pop_string_arg(&mut args, "offset").map(|v| v.parse::<u64>().unwrap());
+        let offset = pop_string_arg(&mut args, "offset")
+            .as_deref()
+            .map(str::parse)
+            .transpose()
+            .map_err(|err| span.error(format!("failed to parse `offset` argument: {}", err)))?;
         err_on_unknown_args(&args)?;
 
-        Ok(KProbe {
+        Ok(Self {
             kind,
             item,
             function,
@@ -46,39 +56,42 @@ impl KProbe {
         })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_name: Cow<'_, _> = if self.function.is_some() && self.offset.is_some() {
-            format!(
-                "{}/{}+{}",
-                self.kind,
-                self.function.as_ref().unwrap(),
-                self.offset.unwrap()
-            )
-            .into()
-        } else if self.function.is_some() {
-            format!("{}/{}", self.kind, self.function.as_ref().unwrap()).into()
-        } else {
-            format!("{}", self.kind).into()
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self {
+            kind,
+            function,
+            offset,
+            item,
+        } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let section_name: Cow<'_, _> = match function {
+            None => self.kind.to_string().into(),
+            Some(function) => match offset {
+                None => format!("{kind}/{function}").into(),
+                Some(offset) => format!("{kind}/{function}+{offset}").into(),
+            },
         };
-
         let probe_type = if section_name.as_ref().starts_with("kprobe") {
             quote! { ProbeContext }
         } else {
             quote! { RetProbeContext }
         };
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
+            #vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
                 let _ = #fn_name(::aya_ebpf::programs::#probe_type::new(ctx));
                 return 0;
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -101,7 +114,7 @@ mod tests {
         )
         .unwrap();
         assert_eq!(
-            kprobe.expand().unwrap().to_string(),
+            kprobe.expand().to_string(),
             quote! {
                 #[no_mangle]
                 #[link_section = "kprobe"]
@@ -133,7 +146,7 @@ mod tests {
         )
         .unwrap();
         assert_eq!(
-            kprobe.expand().unwrap().to_string(),
+            kprobe.expand().to_string(),
             quote! {
                 #[no_mangle]
                 #[link_section = "kprobe/fib_lookup"]
@@ -166,7 +179,7 @@ mod tests {
         )
         .unwrap();
         assert_eq!(
-            kprobe.expand().unwrap().to_string(),
+            kprobe.expand().to_string(),
             quote! {
                 #[no_mangle]
                 #[link_section = "kprobe/fib_lookup+10"]
@@ -196,7 +209,7 @@ mod tests {
         )
         .unwrap();
         assert_eq!(
-            kprobe.expand().unwrap().to_string(),
+            kprobe.expand().to_string(),
             quote! {
                 #[no_mangle]
                 #[link_section = "kretprobe"]

+ 82 - 151
aya-ebpf-macros/src/lib.rs

@@ -37,7 +37,6 @@ use lsm::Lsm;
 use map::Map;
 use perf_event::PerfEvent;
 use proc_macro::TokenStream;
-use proc_macro_error::{abort, proc_macro_error};
 use raw_tracepoint::RawTracePoint;
 use sk_lookup::SkLookup;
 use sk_msg::SkMsg;
@@ -48,83 +47,69 @@ use tc::SchedClassifier;
 use tracepoint::TracePoint;
 use uprobe::{UProbe, UProbeKind};
 use xdp::Xdp;
-#[proc_macro_error]
+
 #[proc_macro_attribute]
 pub fn map(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match Map::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.into_compile_error(),
     }
+    .into()
 }
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn kprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match KProbe::parse(KProbeKind::KProbe, attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn kretprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match KProbe::parse(KProbeKind::KRetProbe, attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn uprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match UProbe::parse(UProbeKind::UProbe, attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => match prog.expand() {
+            Ok(tokens) => tokens,
+            Err(err) => err.emit_as_expr_tokens(),
+        },
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn uretprobe(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match UProbe::parse(UProbeKind::URetProbe, attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => match prog.expand() {
+            Ok(tokens) => tokens,
+            Err(err) => err.emit_as_expr_tokens(),
+        },
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn sock_ops(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match SockOps::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
 
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn sk_msg(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match SkMsg::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
 
 /// Marks a function as an eBPF XDP program that can be attached to a network interface.
@@ -149,60 +134,46 @@ pub fn sk_msg(attrs: TokenStream, item: TokenStream) -> TokenStream {
 ///     XDP_PASS
 /// }
 /// ```
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn xdp(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match Xdp::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn classifier(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match SchedClassifier::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
 
 #[proc_macro_attribute]
 pub fn cgroup_sysctl(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match CgroupSysctl::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn cgroup_sockopt(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match CgroupSockopt::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn cgroup_skb(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match CgroupSkb::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
 
 /// Marks a function as a [`CgroupSockAddr`] eBPF program.
@@ -239,51 +210,39 @@ pub fn cgroup_skb(attrs: TokenStream, item: TokenStream) -> TokenStream {
 ///     Ok(0)
 /// }
 /// ```
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn cgroup_sock_addr(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match CgroupSockAddr::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn cgroup_sock(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match CgroupSock::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
 
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match TracePoint::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
 
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn perf_event(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match PerfEvent::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
 
 /// Marks a function as a raw tracepoint eBPF program that can be attached at a
@@ -314,16 +273,13 @@ pub fn perf_event(attrs: TokenStream, item: TokenStream) -> TokenStream {
 ///     Ok(0)
 /// }
 /// ```
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn raw_tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match RawTracePoint::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.into_compile_error(),
     }
+    .into()
 }
 
 /// Marks a function as an LSM program that can be attached to Linux LSM hooks.
@@ -361,16 +317,13 @@ pub fn raw_tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream {
 ///     Ok(0)
 /// }
 /// ```
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn lsm(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match Lsm::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.into_compile_error(),
     }
+    .into()
 }
 
 /// Marks a function as a [BTF-enabled raw tracepoint][1] eBPF program that can be attached at
@@ -403,16 +356,13 @@ pub fn lsm(attrs: TokenStream, item: TokenStream) -> TokenStream {
 /// ```
 ///
 /// [1]: https://github.com/torvalds/linux/commit/9e15db66136a14cde3f35691f1d839d950118826
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn btf_tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match BtfTracePoint::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.into_compile_error(),
     }
+    .into()
 }
 
 /// Marks a function as a SK_SKB Stream Parser eBPF program that can be attached
@@ -440,7 +390,6 @@ pub fn btf_tracepoint(attrs: TokenStream, item: TokenStream) -> TokenStream {
 ///    Ok(ctx.len())
 ///}
 /// ```
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn stream_parser(attrs: TokenStream, item: TokenStream) -> TokenStream {
     sk_skb(SkSkbKind::StreamParser, attrs, item)
@@ -471,7 +420,6 @@ pub fn stream_parser(attrs: TokenStream, item: TokenStream) -> TokenStream {
 ///    Ok(sk_action::SK_PASS)
 ///}
 /// ```
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn stream_verdict(attrs: TokenStream, item: TokenStream) -> TokenStream {
     sk_skb(SkSkbKind::StreamVerdict, attrs, item)
@@ -479,12 +427,10 @@ pub fn stream_verdict(attrs: TokenStream, item: TokenStream) -> TokenStream {
 
 fn sk_skb(kind: SkSkbKind, attrs: TokenStream, item: TokenStream) -> TokenStream {
     match SkSkb::parse(kind, attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
 
 /// Marks a function as a eBPF Socket Filter program that can be attached to
@@ -504,16 +450,13 @@ fn sk_skb(kind: SkSkbKind, attrs: TokenStream, item: TokenStream) -> TokenStream
 ///     return 0
 /// }
 /// ```
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn socket_filter(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match SocketFilter::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
 
 /// Marks a function as a fentry eBPF program that can be attached to almost
@@ -548,16 +491,13 @@ pub fn socket_filter(attrs: TokenStream, item: TokenStream) -> TokenStream {
 ///     Ok(0)
 /// }
 /// ```
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn fentry(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match FEntry::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.into_compile_error(),
     }
+    .into()
 }
 
 /// Marks a function as a fexit eBPF program that can be attached to almost
@@ -593,16 +533,13 @@ pub fn fentry(attrs: TokenStream, item: TokenStream) -> TokenStream {
 ///     Ok(0)
 /// }
 /// ```
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn fexit(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match FExit::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.into_compile_error(),
     }
+    .into()
 }
 
 /// Marks a function as an eBPF Socket Lookup program that can be attached to
@@ -623,16 +560,13 @@ pub fn fexit(attrs: TokenStream, item: TokenStream) -> TokenStream {
 ///     return 0
 /// }
 /// ```
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn sk_lookup(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match SkLookup::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }
 
 /// Marks a function as a cgroup device eBPF program that can be attached to a
@@ -656,14 +590,11 @@ pub fn sk_lookup(attrs: TokenStream, item: TokenStream) -> TokenStream {
 ///     return 0;
 /// }
 /// ```
-#[proc_macro_error]
 #[proc_macro_attribute]
 pub fn cgroup_device(attrs: TokenStream, item: TokenStream) -> TokenStream {
     match CgroupDevice::parse(attrs.into(), item.into()) {
-        Ok(prog) => prog
-            .expand()
-            .unwrap_or_else(|err| abort!(err.span(), "{}", err))
-            .into(),
-        Err(err) => abort!(err.span(), "{}", err),
+        Ok(prog) => prog.expand(),
+        Err(err) => err.emit_as_expr_tokens(),
     }
+    .into()
 }

+ 22 - 13
aya-ebpf-macros/src/lsm.rs

@@ -13,41 +13,50 @@ pub(crate) struct Lsm {
 }
 
 impl Lsm {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Lsm> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
         let item = syn::parse2(item)?;
         let mut args = syn::parse2(attrs)?;
         let hook = pop_string_arg(&mut args, "hook");
         let sleepable = pop_bool_arg(&mut args, "sleepable");
         err_on_unknown_args(&args)?;
-        Ok(Lsm {
+        Ok(Self {
             item,
             hook,
             sleepable,
         })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_prefix = if self.sleepable { "lsm.s" } else { "lsm" };
-        let section_name: Cow<'_, _> = if let Some(hook) = &self.hook {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self {
+            item,
+            hook,
+            sleepable,
+        } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let section_prefix = if *sleepable { "lsm.s" } else { "lsm" };
+        let section_name: Cow<'_, _> = if let Some(hook) = hook {
             format!("{}/{}", section_prefix, hook).into()
         } else {
             section_prefix.into()
         };
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
         // LSM probes need to return an integer corresponding to the correct
         // policy decision. Therefore we do not simply default to a return value
         // of 0 as in other program types.
-        Ok(quote! {
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
+            #vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
                 return #fn_name(::aya_ebpf::programs::LsmContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -71,7 +80,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "lsm.s/bprm_committed_creds"]
@@ -99,7 +108,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "lsm/bprm_committed_creds"]

+ 7 - 7
aya-ebpf-macros/src/map.rs

@@ -15,18 +15,18 @@ impl Map {
         let item: ItemStatic = syn::parse2(item)?;
         let mut args = syn::parse2(attrs)?;
         let name = name_arg(&mut args).unwrap_or_else(|| item.ident.to_string());
-        Ok(Map { item, name })
+        Ok(Self { item, name })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_name: Cow<'_, _> = "maps".to_string().into();
+    pub(crate) fn expand(&self) -> TokenStream {
+        let section_name: Cow<'_, _> = "maps".into();
         let name = &self.name;
         let item = &self.item;
-        Ok(quote! {
+        quote! {
             #[link_section = #section_name]
             #[export_name = #name]
             #item
-        })
+        }
     }
 }
 
@@ -45,7 +45,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = map.expand().unwrap();
+        let expanded = map.expand();
         let expected = quote!(
             #[link_section = "maps"]
             #[export_name = "foo"]
@@ -63,7 +63,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = map.expand().unwrap();
+        let expanded = map.expand();
         let expected = quote!(
             #[link_section = "maps"]
             #[export_name = "BAR"]

+ 18 - 13
aya-ebpf-macros/src/perf_event.rs

@@ -1,35 +1,40 @@
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 pub(crate) struct PerfEvent {
     item: ItemFn,
 }
 
 impl PerfEvent {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         if !attrs.is_empty() {
-            abort!(attrs, "unexpected attribute")
+            return Err(attrs.span().error("unexpected attribute"));
         }
         let item = syn::parse2(item)?;
-        Ok(PerfEvent { item })
+        Ok(Self { item })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = "perf_event"]
-            #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
+            #vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
                let _ = #fn_name(::aya_ebpf::programs::PerfEventContext::new(ctx));
                return 0;
 
                #item
             }
-        })
+        }
     }
 }
 
@@ -50,7 +55,7 @@ mod tests {
             ),
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "perf_event"]

+ 16 - 11
aya-ebpf-macros/src/raw_tracepoint.rs

@@ -12,33 +12,38 @@ pub(crate) struct RawTracePoint {
 }
 
 impl RawTracePoint {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<RawTracePoint> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
         let item = syn::parse2(item)?;
         let mut args = syn::parse2(attrs)?;
         let tracepoint = pop_string_arg(&mut args, "tracepoint");
         err_on_unknown_args(&args)?;
-        Ok(RawTracePoint { item, tracepoint })
+        Ok(Self { item, tracepoint })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_name: Cow<'_, _> = if let Some(tracepoint) = &self.tracepoint {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item, tracepoint } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let section_name: Cow<'_, _> = if let Some(tracepoint) = tracepoint {
             format!("raw_tp/{}", tracepoint).into()
         } else {
             "raw_tp".into()
         };
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
+            #vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
                 let _ = #fn_name(::aya_ebpf::programs::RawTracePointContext::new(ctx));
                 return 0;
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -59,7 +64,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "raw_tp/sys_enter"]

+ 18 - 13
aya-ebpf-macros/src/sk_lookup.rs

@@ -1,34 +1,39 @@
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 pub(crate) struct SkLookup {
     item: ItemFn,
 }
 
 impl SkLookup {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         if !attrs.is_empty() {
-            abort!(attrs, "unexpected attribute")
+            return Err(attrs.span().error("unexpected attribute"));
         }
         let item = syn::parse2(item)?;
-        Ok(SkLookup { item })
+        Ok(Self { item })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let fn_name = self.item.sig.ident.clone();
-        let fn_vis = &self.item.vis;
-        let item = &self.item;
-        Ok(quote! {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = "sk_lookup"]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sk_lookup) -> u32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sk_lookup) -> u32 {
                 return #fn_name(::aya_ebpf::programs::SkLookupContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -49,7 +54,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "sk_lookup"]

+ 18 - 13
aya-ebpf-macros/src/sk_msg.rs

@@ -1,34 +1,39 @@
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 pub(crate) struct SkMsg {
     item: ItemFn,
 }
 
 impl SkMsg {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         if !attrs.is_empty() {
-            abort!(attrs, "unexpected attribute")
+            return Err(attrs.span().error("unexpected attribute"));
         }
         let item = syn::parse2(item)?;
-        Ok(SkMsg { item })
+        Ok(Self { item })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = "sk_msg"]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::sk_msg_md) -> u32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::sk_msg_md) -> u32 {
                 return #fn_name(::aya_ebpf::programs::SkMsgContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -49,7 +54,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "sk_msg"]

+ 23 - 15
aya-ebpf-macros/src/sk_skb.rs

@@ -1,9 +1,9 @@
 use std::borrow::Cow;
 
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 #[allow(clippy::enum_variant_names)]
 #[derive(Debug, Copy, Clone)]
@@ -28,29 +28,37 @@ pub(crate) struct SkSkb {
 }
 
 impl SkSkb {
-    pub(crate) fn parse(kind: SkSkbKind, attrs: TokenStream, item: TokenStream) -> Result<SkSkb> {
+    pub(crate) fn parse(
+        kind: SkSkbKind,
+        attrs: TokenStream,
+        item: TokenStream,
+    ) -> Result<Self, Diagnostic> {
         if !attrs.is_empty() {
-            abort!(attrs, "unexpected attribute");
+            return Err(attrs.span().error("unexpected attribute"));
         }
         let item = syn::parse2(item)?;
-        Ok(SkSkb { item, kind })
+        Ok(Self { item, kind })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let kind = &self.kind;
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { kind, item } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
         let section_name: Cow<'_, _> = format!("sk_skb/{kind}").into();
-        let fn_name = self.item.sig.ident.clone();
-        let fn_vis = &self.item.vis;
-        let item = &self.item;
-        Ok(quote! {
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::__sk_buff) -> u32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::__sk_buff) -> u32 {
                 return #fn_name(::aya_ebpf::programs::SkBuffContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -72,7 +80,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "sk_skb/stream_parser"]
@@ -99,7 +107,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "sk_skb/stream_verdict"]

+ 18 - 13
aya-ebpf-macros/src/sock_ops.rs

@@ -1,34 +1,39 @@
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 pub(crate) struct SockOps {
     item: ItemFn,
 }
 
 impl SockOps {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         if !attrs.is_empty() {
-            abort!(attrs, "unexpected attribute")
+            return Err(attrs.span().error("unexpected attribute"));
         }
         let item = syn::parse2(item)?;
-        Ok(SockOps { item })
+        Ok(Self { item })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = "sockops"]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sock_ops) -> u32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::bpf_sock_ops) -> u32 {
                 return #fn_name(::aya_ebpf::programs::SockOpsContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -49,7 +54,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "sockops"]

+ 18 - 13
aya-ebpf-macros/src/socket_filter.rs

@@ -1,34 +1,39 @@
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 pub(crate) struct SocketFilter {
     item: ItemFn,
 }
 
 impl SocketFilter {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         if !attrs.is_empty() {
-            abort!(attrs, "unexpected attribute")
+            return Err(attrs.span().error("unexpected attribute"));
         }
         let item = syn::parse2(item)?;
-        Ok(SocketFilter { item })
+        Ok(Self { item })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let fn_name = self.item.sig.ident.clone();
-        let fn_vis = &self.item.vis;
-        let item = &self.item;
-        Ok(quote! {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = "socket"]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::__sk_buff) -> i64 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::__sk_buff) -> i64 {
                 return #fn_name(::aya_ebpf::programs::SkBuffContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -49,7 +54,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "socket"]

+ 18 - 13
aya-ebpf-macros/src/tc.rs

@@ -1,34 +1,39 @@
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 pub(crate) struct SchedClassifier {
     item: ItemFn,
 }
 
 impl SchedClassifier {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         if !attrs.is_empty() {
-            abort!(attrs, "unexpected attribute")
+            return Err(attrs.span().error("unexpected attribute"));
         }
         let item = syn::parse2(item)?;
-        Ok(SchedClassifier { item })
+        Ok(Self { item })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = "classifier"]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::__sk_buff) -> i32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::__sk_buff) -> i32 {
                 return #fn_name(::aya_ebpf::programs::TcContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -49,7 +54,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "classifier"]

+ 35 - 23
aya-ebpf-macros/src/tracepoint.rs

@@ -1,52 +1,64 @@
 use std::borrow::Cow;
 
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 use crate::args::{err_on_unknown_args, pop_string_arg};
 
 pub(crate) struct TracePoint {
     item: ItemFn,
-    category: Option<String>,
-    name: Option<String>,
+    name_and_category: Option<(String, String)>,
 }
 
 impl TracePoint {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<TracePoint> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         let item = syn::parse2(item)?;
+        let span = attrs.span();
         let mut args = syn::parse2(attrs)?;
         let name = pop_string_arg(&mut args, "name");
         let category = pop_string_arg(&mut args, "category");
         err_on_unknown_args(&args)?;
-        Ok(TracePoint {
-            item,
-            category,
-            name,
-        })
+        match (name, category) {
+            (None, None) => Ok(Self {
+                item,
+                name_and_category: None,
+            }),
+            (Some(name), Some(category)) => Ok(Self {
+                item,
+                name_and_category: Some((name, category)),
+            }),
+            _ => Err(span.error("expected `name` and `category` arguments")),
+        }
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let section_name: Cow<'_, _> = match (&self.category, &self.name) {
-            (Some(category), Some(name)) => format!("tracepoint/{}/{}", category, name).into(),
-            (Some(_), None) => abort!(self.item, "expected `name` and `category` arguments"),
-            (None, Some(_)) => abort!(self.item, "expected `name` and `category` arguments"),
-            _ => "tracepoint".into(),
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self {
+            item,
+            name_and_category,
+        } = self;
+        let section_name: Cow<'_, _> = match name_and_category {
+            Some((name, category)) => format!("tracepoint/{category}/{name}").into(),
+            None => "tracepoint".into(),
         };
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
+            #vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
                let _ = #fn_name(::aya_ebpf::programs::TracePointContext::new(ctx));
                return 0;
 
                #item
             }
-        })
+        }
     }
 }
 
@@ -67,7 +79,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "tracepoint/syscalls/sys_enter_bind"]

+ 47 - 41
aya-ebpf-macros/src/uprobe.rs

@@ -1,9 +1,9 @@
 use std::borrow::Cow;
 
 use proc_macro2::TokenStream;
-use proc_macro_error::abort;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 use crate::args::{err_on_unknown_args, pop_bool_arg, pop_string_arg};
 
@@ -34,15 +34,24 @@ pub(crate) struct UProbe {
 }
 
 impl UProbe {
-    pub(crate) fn parse(kind: UProbeKind, attrs: TokenStream, item: TokenStream) -> Result<UProbe> {
+    pub(crate) fn parse(
+        kind: UProbeKind,
+        attrs: TokenStream,
+        item: TokenStream,
+    ) -> Result<Self, Diagnostic> {
         let item = syn::parse2(item)?;
+        let span = attrs.span();
         let mut args = syn::parse2(attrs)?;
         let path = pop_string_arg(&mut args, "path");
         let function = pop_string_arg(&mut args, "function");
-        let offset = pop_string_arg(&mut args, "offset").map(|v| v.parse::<u64>().unwrap());
+        let offset = pop_string_arg(&mut args, "offset")
+            .as_deref()
+            .map(str::parse)
+            .transpose()
+            .map_err(|err| span.error(format!("failed to parse `offset` argument: {}", err)))?;
         let sleepable = pop_bool_arg(&mut args, "sleepable");
         err_on_unknown_args(&args)?;
-        Ok(UProbe {
+        Ok(Self {
             kind,
             item,
             path,
@@ -52,39 +61,38 @@ impl UProbe {
         })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let prefix = if self.sleepable {
-            format!("{}.s", self.kind)
-        } else {
-            format!("{}", self.kind)
-        };
-        let section_name: Cow<'_, _> = if self.path.is_some() && self.offset.is_some() {
-            if self.function.is_none() {
-                abort!(self.item.sig.ident, "expected `function` attribute");
-            }
-            let mut path = self.path.as_ref().unwrap().clone();
-            if path.starts_with('/') {
-                path.remove(0);
-            }
-            format!(
-                "{}/{}:{}+{}",
-                prefix,
-                path,
-                self.function.as_ref().unwrap(),
-                self.offset.unwrap()
-            )
-            .into()
-        } else if self.path.is_some() {
-            if self.function.is_none() {
-                abort!(self.item.sig.ident, "expected `function` attribute");
-            }
-            let mut path = self.path.as_ref().unwrap().clone();
-            if path.starts_with('/') {
-                path.remove(0);
+    pub(crate) fn expand(&self) -> Result<TokenStream, Diagnostic> {
+        let Self {
+            kind,
+            path,
+            function,
+            offset,
+            item,
+            sleepable,
+        } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let mut prefix = kind.to_string();
+        if *sleepable {
+            prefix.push_str(".s");
+        }
+        let section_name: Cow<'_, _> = match path {
+            None => prefix.into(),
+            Some(path) => {
+                let path = path.strip_prefix("/").unwrap_or(path);
+                // TODO: check this in parse instead.
+                let function = function
+                    .as_deref()
+                    .ok_or(item.sig.span().error("expected `function` attribute"))?;
+                match offset {
+                    None => format!("{prefix}/{path}:{function}").into(),
+                    Some(offset) => format!("{prefix}/{path}:{function}+{offset}",).into(),
+                }
             }
-            format!("{}/{}:{}", prefix, path, self.function.as_ref().unwrap()).into()
-        } else {
-            prefix.to_string().into()
         };
 
         let probe_type = if section_name.as_ref().starts_with("uprobe") {
@@ -92,13 +100,11 @@ impl UProbe {
         } else {
             quote! { RetProbeContext }
         };
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
+        let fn_name = &sig.ident;
         Ok(quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
+            #vis fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
                 let _ = #fn_name(::aya_ebpf::programs::#probe_type::new(ctx));
                 return 0;
 

+ 28 - 23
aya-ebpf-macros/src/xdp.rs

@@ -1,6 +1,7 @@
 use proc_macro2::TokenStream;
+use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt as _};
 use quote::quote;
-use syn::{Error, ItemFn, Result};
+use syn::{spanned::Spanned as _, ItemFn};
 
 use crate::args::{err_on_unknown_args, pop_bool_arg, pop_string_arg, Args};
 
@@ -17,8 +18,9 @@ pub(crate) enum XdpMap {
 }
 
 impl Xdp {
-    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Xdp> {
+    pub(crate) fn parse(attrs: TokenStream, item: TokenStream) -> Result<Self, Diagnostic> {
         let item = syn::parse2(item)?;
+        let span = attrs.span();
         let mut args: Args = syn::parse2(attrs)?;
 
         let frags = pop_bool_arg(&mut args, "frags");
@@ -26,39 +28,42 @@ impl Xdp {
             Some("cpumap") => Some(XdpMap::CpuMap),
             Some("devmap") => Some(XdpMap::DevMap),
             Some(name) => {
-                return Err(Error::new_spanned(
-                    "map",
-                    format!("Invalid value. Expected 'cpumap' or 'devmap', found '{name}'"),
-                ))
+                return Err(span.error(format!(
+                    "Invalid value. Expected 'cpumap' or 'devmap', found '{name}'"
+                )))
             }
             None => None,
         };
 
         err_on_unknown_args(&args)?;
-        Ok(Xdp { item, frags, map })
+        Ok(Self { item, frags, map })
     }
 
-    pub(crate) fn expand(&self) -> Result<TokenStream> {
-        let mut section_name = vec![if self.frags { "xdp.frags" } else { "xdp" }];
-        match self.map {
+    pub(crate) fn expand(&self) -> TokenStream {
+        let Self { item, frags, map } = self;
+        let ItemFn {
+            attrs: _,
+            vis,
+            sig,
+            block: _,
+        } = item;
+        let mut section_name = vec![if *frags { "xdp.frags" } else { "xdp" }];
+        match map {
             Some(XdpMap::CpuMap) => section_name.push("cpumap"),
             Some(XdpMap::DevMap) => section_name.push("devmap"),
             None => (),
         };
         let section_name = section_name.join("/");
-
-        let fn_vis = &self.item.vis;
-        let fn_name = self.item.sig.ident.clone();
-        let item = &self.item;
-        Ok(quote! {
+        let fn_name = &sig.ident;
+        quote! {
             #[no_mangle]
             #[link_section = #section_name]
-            #fn_vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::xdp_md) -> u32 {
+            #vis fn #fn_name(ctx: *mut ::aya_ebpf::bindings::xdp_md) -> u32 {
                 return #fn_name(::aya_ebpf::programs::XdpContext::new(ctx));
 
                 #item
             }
-        })
+        }
     }
 }
 
@@ -79,7 +84,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "xdp"]
@@ -105,7 +110,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "xdp.frags"]
@@ -131,7 +136,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "xdp/cpumap"]
@@ -157,7 +162,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "xdp/devmap"]
@@ -197,7 +202,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "xdp.frags/cpumap"]
@@ -223,7 +228,7 @@ mod tests {
             },
         )
         .unwrap();
-        let expanded = prog.expand().unwrap();
+        let expanded = prog.expand();
         let expected = quote! {
             #[no_mangle]
             #[link_section = "xdp.frags/devmap"]