From 899cda32ad6667fb6b1880584baa1ffe5706547a Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Fri, 27 Sep 2024 00:34:35 +0200 Subject: [PATCH] Suppress spurious unneeded parenthesis warnings from the generated code when a parenthesis-delimited expression is interpolated as the only argument of a function call. --- plugin/src/common.rs | 49 +++++++++++++++++++++++++++++++++-------- plugin/src/serialize.rs | 19 ++++++++++++---- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/plugin/src/common.rs b/plugin/src/common.rs index 02b644c00..a8e927a4f 100644 --- a/plugin/src/common.rs +++ b/plugin/src/common.rs @@ -1,5 +1,5 @@ //! This module contains various infrastructure that is common across all assembler backends -use proc_macro2::{Span, TokenTree, TokenStream, Literal, Group}; +use proc_macro2::{Span, TokenTree, TokenStream, Literal, Group, Delimiter}; use quote::ToTokens; use syn::spanned::Spanned; use syn::parse; @@ -246,13 +246,13 @@ impl Stmt { } -// Takes an arbitrary tokenstream as input, and ensures it can be interpolated safely. -// returns a tokentree representing either a single token, or a delimited group. -// -// If the given tokenstream contains multiple tokens, it will be parenthesized. -// -// this will panic if given an empty tokenstream. -// this would use delimiter::None if not for https://github.com/rust-lang/rust/issues/67062 +/// Takes an arbitrary tokenstream as input, and ensures it can be interpolated safely. +/// returns a tokentree representing either a single token, or a delimited group. +/// +/// If the given tokenstream contains multiple tokens, it will be parenthesized. +/// +/// this will panic if given an empty tokenstream. +/// this would use delimiter::None if not for https://github.com/rust-lang/rust/issues/67062 pub fn delimited(expr: T) -> TokenTree { let stream = expr.into_token_stream(); @@ -269,7 +269,38 @@ pub fn delimited(expr: T) -> TokenTree { proc_macro2::Delimiter::Parenthesis, stream ); group.set_span(span); - proc_macro2::TokenTree::Group(group) + TokenTree::Group(group) +} + +/// Checks if the given tokenstream is a parenthesized expression to work around rustc giving +/// Unnecessary parenthesis warnings in macro-generated code, if this tokentree were to be used +/// as the argument to a single argument function +/// +/// i.e. `function(#arg)` expanding to `function((expr))`, which should instead be expanded to +/// `function(expr)` +/// +/// To check if this is valid, we should a: test that this tokentree node is a parenthesis delimited +/// node and b: there are no commas in its internal tokentree, because then it'd be a tuple, and +/// this transform would be invalid +pub fn is_parenthesized(expr: &TokenTree) -> bool { + match expr { + TokenTree::Group(group) => { + if group.delimiter() != Delimiter::Parenthesis { + return false + } + + for item in group.stream() { + if let TokenTree::Punct(punct) = item { + if punct.as_char() == ',' { + return false + } + } + } + + true + }, + _ => false + } } /// Create a bitmask with `scale` bits set diff --git a/plugin/src/serialize.rs b/plugin/src/serialize.rs index 03590100c..c7f91e162 100644 --- a/plugin/src/serialize.rs +++ b/plugin/src/serialize.rs @@ -6,7 +6,7 @@ use quote::{quote, quote_spanned, ToTokens}; use byteorder::{ByteOrder, LittleEndian}; -use crate::common::{Size, Stmt, delimited, Relocation}; +use crate::common::{Size, Stmt, delimited, is_parenthesized, Relocation}; use std::convert::TryInto; @@ -103,9 +103,20 @@ pub fn serialize(name: &TokenTree, stmts: Vec) -> TokenStream { // and construct the appropriate method call let method = syn::Ident::new(method, Span::mixed_site()); - output.extend(quote! { - #name . #method ( #( #args ),* ) ; - }) + + if args.len() == 1 && is_parenthesized(&args[0]) { + // special case for not emitting redundant parenthesis to work around an annoying error + let mut args = args; + let arg = args.pop().unwrap(); + output.extend(quote! { + #name . #method #arg ; + }) + + } else { + output.extend(quote! { + #name . #method ( #( #args ),* ) ; + }) + } } // if we have nothing to emit, expand to nothing. Else, wrap it into a block.