// Copyright 2019 The Fuchsia Authors // // Licensed under a BSD-style license , Apache License, Version 2.0 // , or the MIT // license , at your option. // This file may not be copied, modified, or distributed except according to // those terms. //! Derive macros for [zerocopy]'s traits. //! //! [zerocopy]: https://docs.rs/zerocopy // Sometimes we want to use lints which were added after our MSRV. // `unknown_lints` is `warn` by default and we deny warnings in CI, so without // this attribute, any unknown lint would cause a CI failure when testing with // our MSRV. #![allow(unknown_lints)] #![deny(renamed_and_removed_lints)] #![deny( clippy::all, clippy::missing_safety_doc, clippy::multiple_unsafe_ops_per_block, clippy::undocumented_unsafe_blocks )] // We defer to own discretion on type complexity. #![allow(clippy::type_complexity)] // Inlining format args isn't supported on our MSRV. #![allow(clippy::uninlined_format_args)] #![deny( rustdoc::bare_urls, rustdoc::broken_intra_doc_links, rustdoc::invalid_codeblock_attributes, rustdoc::invalid_html_tags, rustdoc::invalid_rust_codeblocks, rustdoc::missing_crate_level_docs, rustdoc::private_intra_doc_links )] #![recursion_limit = "128"] macro_rules! ident { (($fmt:literal $(, $arg:expr)*), $span:expr) => { syn::Ident::new(&format!($fmt $(, crate::util::to_ident_str($arg))*), $span) }; } mod derive; #[cfg(test)] mod output_tests; mod repr; mod util; use syn::{DeriveInput, Error}; use crate::util::*; // FIXME(https://github.com/rust-lang/rust/issues/54140): Some errors could be // made better if we could add multiple lines of error output like this: // // error: unsupported representation // --> enum.rs:28:8 // | // 28 | #[repr(transparent)] // | // help: required by the derive of FromBytes // // Instead, we have more verbose error messages like "unsupported representation // for deriving FromZeros, FromBytes, IntoBytes, or Unaligned on an enum" // // This will probably require Span::error // (https://doc.rust-lang.org/nightly/proc_macro/struct.Span.html#method.error), // which is currently unstable. Revisit this once it's stable. /// Defines a derive function named `$outer` which parses its input /// `TokenStream` as a `DeriveInput` and then invokes the `$inner` function. /// /// Note that the separate `$outer` parameter is required - proc macro functions /// are currently required to live at the crate root, and so the caller must /// specify the name in order to avoid name collisions. macro_rules! derive { ($trait:ident => $outer:ident => $inner:path) => { #[proc_macro_derive($trait, attributes(zerocopy))] pub fn $outer(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { let ast = syn::parse_macro_input!(ts as DeriveInput); let ctx = match Ctx::try_from_derive_input(ast) { Ok(ctx) => ctx, Err(e) => return e.into_compile_error().into(), }; let ts = $inner(&ctx, Trait::$trait).into_ts(); // We wrap in `const_block` as a backstop in case any derive fails // to wrap its output in `const_block` (and thus fails to annotate) // with the full set of `#[allow(...)]` attributes). let ts = const_block([Some(ts)]); #[cfg(test)] crate::util::testutil::check_hygiene(ts.clone()); ts.into() } }; } trait IntoTokenStream { fn into_ts(self) -> proc_macro2::TokenStream; } impl IntoTokenStream for proc_macro2::TokenStream { fn into_ts(self) -> proc_macro2::TokenStream { self } } impl IntoTokenStream for Result { fn into_ts(self) -> proc_macro2::TokenStream { match self { Ok(ts) => ts, Err(err) => err.to_compile_error(), } } } derive!(KnownLayout => derive_known_layout => crate::derive::known_layout::derive); derive!(Immutable => derive_immutable => crate::derive::derive_immutable); derive!(TryFromBytes => derive_try_from_bytes => crate::derive::try_from_bytes::derive_try_from_bytes); derive!(FromZeros => derive_from_zeros => crate::derive::from_bytes::derive_from_zeros); derive!(FromBytes => derive_from_bytes => crate::derive::from_bytes::derive_from_bytes); derive!(IntoBytes => derive_into_bytes => crate::derive::into_bytes::derive_into_bytes); derive!(Unaligned => derive_unaligned => crate::derive::unaligned::derive_unaligned); derive!(ByteHash => derive_hash => crate::derive::derive_hash); derive!(ByteEq => derive_eq => crate::derive::derive_eq); derive!(SplitAt => derive_split_at => crate::derive::derive_split_at); /// Deprecated: prefer [`FromZeros`] instead. #[deprecated(since = "0.8.0", note = "`FromZeroes` was renamed to `FromZeros`")] #[doc(hidden)] #[proc_macro_derive(FromZeroes)] pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { derive_from_zeros(ts) } /// Deprecated: prefer [`IntoBytes`] instead. #[deprecated(since = "0.8.0", note = "`AsBytes` was renamed to `IntoBytes`")] #[doc(hidden)] #[proc_macro_derive(AsBytes)] pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { derive_into_bytes(ts) }