mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
rust: pin-init: internal: handle item and expr diagnostics differently
Currently `DiagCtxt` is used to allow error recovery in the pin-init
macros, by generating both a `compile_error!()` macro item and continue
expansion, and then merge token streams together. This works very well for
items, however for expressions, this will produce invalid expression and
result in a confusing error message.
error: macro expansion ignores `::` and any tokens following
--> tests/ui/compile-fail/zeroable/invalid_spread.rs:15:9
|
13 | let _ = init!(Foo {
| _____________-
14 | | a: 0,
15 | | ..MyZeroable::init_zeroed()
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
16 | | });
| |______- caused by the macro expansion here
|
= note: the usage of `init!` is likely invalid in expression context
Fix this by wrap the concatenated diagnostics in a block, with the
generated expression in its tail position. This results in the desired
error message.
error: expected nothing or `..Zeroable::init_zeroed()`.
--> tests/ui/compile-fail/zeroable/invalid_spread.rs:15:9
|
15 | ..MyZeroable::init_zeroed()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
Reviewed-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20260923140618.1978181-1-gary@kernel.org
Signed-off-by: Gary Guo <gary@garyguo.net>
This commit is contained in:
parent
666b3e7cfa
commit
01c3d218e8
|
|
@ -3,7 +3,7 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote_spanned;
|
||||
use quote::{quote, quote_spanned};
|
||||
use syn::{spanned::Spanned, Error};
|
||||
|
||||
pub(crate) struct DiagCtxt(TokenStream);
|
||||
|
|
@ -29,16 +29,55 @@ const fn warn() {}
|
|||
));
|
||||
}
|
||||
|
||||
pub(crate) fn with(
|
||||
fun: impl FnOnce(&mut DiagCtxt) -> Result<TokenStream, ErrorGuaranteed>,
|
||||
fn with(
|
||||
f: impl FnOnce(&mut DiagCtxt) -> Result<TokenStream, ErrorGuaranteed>,
|
||||
merge_diag: impl FnOnce(TokenStream, TokenStream) -> TokenStream,
|
||||
convert_diag: impl FnOnce(TokenStream) -> TokenStream,
|
||||
) -> TokenStream {
|
||||
let mut dcx = Self(TokenStream::new());
|
||||
match fun(&mut dcx) {
|
||||
Ok(mut stream) => {
|
||||
stream.extend(dcx.0);
|
||||
stream
|
||||
match f(&mut dcx) {
|
||||
Ok(stream) => {
|
||||
if dcx.0.is_empty() {
|
||||
stream
|
||||
} else {
|
||||
merge_diag(stream, dcx.0)
|
||||
}
|
||||
}
|
||||
Err(ErrorGuaranteed(())) => dcx.0,
|
||||
Err(ErrorGuaranteed(())) => convert_diag(dcx.0),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn for_item(
|
||||
f: impl FnOnce(&mut DiagCtxt) -> Result<TokenStream, ErrorGuaranteed>,
|
||||
) -> TokenStream {
|
||||
Self::with(
|
||||
f,
|
||||
|mut out, diag| {
|
||||
out.extend(diag);
|
||||
out
|
||||
},
|
||||
std::convert::identity,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn for_expr(
|
||||
f: impl FnOnce(&mut DiagCtxt) -> Result<TokenStream, ErrorGuaranteed>,
|
||||
) -> TokenStream {
|
||||
Self::with(
|
||||
f,
|
||||
|out, diag| {
|
||||
// Diagnostics that we generate are always items.
|
||||
// So for expressions create a block to place diagnostics in item position.
|
||||
quote!({
|
||||
#diag
|
||||
#out
|
||||
})
|
||||
},
|
||||
|diag| {
|
||||
quote!({
|
||||
#diag
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,31 +25,31 @@
|
|||
pub fn pin_data(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let args = parse_macro_input!(args);
|
||||
let input = parse_macro_input!(input);
|
||||
DiagCtxt::with(|dcx| pin_data::pin_data(args, input, dcx)).into()
|
||||
DiagCtxt::for_item(|dcx| pin_data::pin_data(args, input, dcx)).into()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let args = parse_macro_input!(args);
|
||||
let input = parse_macro_input!(input);
|
||||
DiagCtxt::with(|dcx| pinned_drop::pinned_drop(args, input, dcx)).into()
|
||||
DiagCtxt::for_item(|dcx| pinned_drop::pinned_drop(args, input, dcx)).into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(Zeroable)]
|
||||
pub fn derive_zeroable(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input);
|
||||
DiagCtxt::with(|dcx| zeroable::derive(input, dcx)).into()
|
||||
DiagCtxt::for_item(|dcx| zeroable::derive(input, dcx)).into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(MaybeZeroable)]
|
||||
pub fn maybe_derive_zeroable(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input);
|
||||
DiagCtxt::with(|dcx| zeroable::maybe_derive(input, dcx)).into()
|
||||
DiagCtxt::for_item(|dcx| zeroable::maybe_derive(input, dcx)).into()
|
||||
}
|
||||
#[proc_macro]
|
||||
pub fn init(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input);
|
||||
DiagCtxt::with(|dcx| {
|
||||
DiagCtxt::for_expr(|dcx| {
|
||||
init::expand_with_cfg(input, Some("::core::convert::Infallible"), false, dcx)
|
||||
})
|
||||
.into()
|
||||
|
|
@ -58,7 +58,7 @@ pub fn init(input: TokenStream) -> TokenStream {
|
|||
#[proc_macro]
|
||||
pub fn pin_init(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input);
|
||||
DiagCtxt::with(|dcx| {
|
||||
DiagCtxt::for_expr(|dcx| {
|
||||
init::expand_with_cfg(input, Some("::core::convert::Infallible"), true, dcx)
|
||||
})
|
||||
.into()
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user