1*5f85604cSMiguel Ojeda // SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT 2*5f85604cSMiguel Ojeda 3b437b383SMiguel Ojeda // Copyright 2019 The Fuchsia Authors 4b437b383SMiguel Ojeda // 5b437b383SMiguel Ojeda // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0 6b437b383SMiguel Ojeda // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT 7b437b383SMiguel Ojeda // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. 8b437b383SMiguel Ojeda // This file may not be copied, modified, or distributed except according to 9b437b383SMiguel Ojeda // those terms. 10b437b383SMiguel Ojeda 11b437b383SMiguel Ojeda //! Derive macros for [zerocopy]'s traits. 12b437b383SMiguel Ojeda //! 13b437b383SMiguel Ojeda //! [zerocopy]: https://docs.rs/zerocopy 14b437b383SMiguel Ojeda 15b437b383SMiguel Ojeda // Sometimes we want to use lints which were added after our MSRV. 16b437b383SMiguel Ojeda // `unknown_lints` is `warn` by default and we deny warnings in CI, so without 17b437b383SMiguel Ojeda // this attribute, any unknown lint would cause a CI failure when testing with 18b437b383SMiguel Ojeda // our MSRV. 19b437b383SMiguel Ojeda #![allow(unknown_lints)] 20b437b383SMiguel Ojeda #![deny(renamed_and_removed_lints)] 21b437b383SMiguel Ojeda #![deny( 22b437b383SMiguel Ojeda clippy::all, 23b437b383SMiguel Ojeda clippy::missing_safety_doc, 24b437b383SMiguel Ojeda clippy::multiple_unsafe_ops_per_block, 25b437b383SMiguel Ojeda clippy::undocumented_unsafe_blocks 26b437b383SMiguel Ojeda )] 27b437b383SMiguel Ojeda // We defer to own discretion on type complexity. 28b437b383SMiguel Ojeda #![allow(clippy::type_complexity)] 29b437b383SMiguel Ojeda // Inlining format args isn't supported on our MSRV. 30b437b383SMiguel Ojeda #![allow(clippy::uninlined_format_args)] 31b437b383SMiguel Ojeda #![deny( 32b437b383SMiguel Ojeda rustdoc::bare_urls, 33b437b383SMiguel Ojeda rustdoc::broken_intra_doc_links, 34b437b383SMiguel Ojeda rustdoc::invalid_codeblock_attributes, 35b437b383SMiguel Ojeda rustdoc::invalid_html_tags, 36b437b383SMiguel Ojeda rustdoc::invalid_rust_codeblocks, 37b437b383SMiguel Ojeda rustdoc::missing_crate_level_docs, 38b437b383SMiguel Ojeda rustdoc::private_intra_doc_links 39b437b383SMiguel Ojeda )] 40b437b383SMiguel Ojeda #![recursion_limit = "128"] 41b437b383SMiguel Ojeda 42b437b383SMiguel Ojeda macro_rules! ident { 43b437b383SMiguel Ojeda (($fmt:literal $(, $arg:expr)*), $span:expr) => { 44b437b383SMiguel Ojeda syn::Ident::new(&format!($fmt $(, crate::util::to_ident_str($arg))*), $span) 45b437b383SMiguel Ojeda }; 46b437b383SMiguel Ojeda } 47b437b383SMiguel Ojeda 48b437b383SMiguel Ojeda mod derive; 49b437b383SMiguel Ojeda #[cfg(test)] 50b437b383SMiguel Ojeda mod output_tests; 51b437b383SMiguel Ojeda mod repr; 52b437b383SMiguel Ojeda mod util; 53b437b383SMiguel Ojeda 54b437b383SMiguel Ojeda use syn::{DeriveInput, Error}; 55b437b383SMiguel Ojeda 56b437b383SMiguel Ojeda use crate::util::*; 57b437b383SMiguel Ojeda 58b437b383SMiguel Ojeda // FIXME(https://github.com/rust-lang/rust/issues/54140): Some errors could be 59b437b383SMiguel Ojeda // made better if we could add multiple lines of error output like this: 60b437b383SMiguel Ojeda // 61b437b383SMiguel Ojeda // error: unsupported representation 62b437b383SMiguel Ojeda // --> enum.rs:28:8 63b437b383SMiguel Ojeda // | 64b437b383SMiguel Ojeda // 28 | #[repr(transparent)] 65b437b383SMiguel Ojeda // | 66b437b383SMiguel Ojeda // help: required by the derive of FromBytes 67b437b383SMiguel Ojeda // 68b437b383SMiguel Ojeda // Instead, we have more verbose error messages like "unsupported representation 69b437b383SMiguel Ojeda // for deriving FromZeros, FromBytes, IntoBytes, or Unaligned on an enum" 70b437b383SMiguel Ojeda // 71b437b383SMiguel Ojeda // This will probably require Span::error 72b437b383SMiguel Ojeda // (https://doc.rust-lang.org/nightly/proc_macro/struct.Span.html#method.error), 73b437b383SMiguel Ojeda // which is currently unstable. Revisit this once it's stable. 74b437b383SMiguel Ojeda 75b437b383SMiguel Ojeda /// Defines a derive function named `$outer` which parses its input 76b437b383SMiguel Ojeda /// `TokenStream` as a `DeriveInput` and then invokes the `$inner` function. 77b437b383SMiguel Ojeda /// 78b437b383SMiguel Ojeda /// Note that the separate `$outer` parameter is required - proc macro functions 79b437b383SMiguel Ojeda /// are currently required to live at the crate root, and so the caller must 80b437b383SMiguel Ojeda /// specify the name in order to avoid name collisions. 81b437b383SMiguel Ojeda macro_rules! derive { 82b437b383SMiguel Ojeda ($trait:ident => $outer:ident => $inner:path) => { 83b437b383SMiguel Ojeda #[proc_macro_derive($trait, attributes(zerocopy))] 84b437b383SMiguel Ojeda pub fn $outer(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { 85b437b383SMiguel Ojeda let ast = syn::parse_macro_input!(ts as DeriveInput); 86b437b383SMiguel Ojeda let ctx = match Ctx::try_from_derive_input(ast) { 87b437b383SMiguel Ojeda Ok(ctx) => ctx, 88b437b383SMiguel Ojeda Err(e) => return e.into_compile_error().into(), 89b437b383SMiguel Ojeda }; 90b437b383SMiguel Ojeda let ts = $inner(&ctx, Trait::$trait).into_ts(); 91b437b383SMiguel Ojeda // We wrap in `const_block` as a backstop in case any derive fails 92b437b383SMiguel Ojeda // to wrap its output in `const_block` (and thus fails to annotate) 93b437b383SMiguel Ojeda // with the full set of `#[allow(...)]` attributes). 94b437b383SMiguel Ojeda let ts = const_block([Some(ts)]); 95b437b383SMiguel Ojeda #[cfg(test)] 96b437b383SMiguel Ojeda crate::util::testutil::check_hygiene(ts.clone()); 97b437b383SMiguel Ojeda ts.into() 98b437b383SMiguel Ojeda } 99b437b383SMiguel Ojeda }; 100b437b383SMiguel Ojeda } 101b437b383SMiguel Ojeda 102b437b383SMiguel Ojeda trait IntoTokenStream { 103b437b383SMiguel Ojeda fn into_ts(self) -> proc_macro2::TokenStream; 104b437b383SMiguel Ojeda } 105b437b383SMiguel Ojeda 106b437b383SMiguel Ojeda impl IntoTokenStream for proc_macro2::TokenStream { 107b437b383SMiguel Ojeda fn into_ts(self) -> proc_macro2::TokenStream { 108b437b383SMiguel Ojeda self 109b437b383SMiguel Ojeda } 110b437b383SMiguel Ojeda } 111b437b383SMiguel Ojeda 112b437b383SMiguel Ojeda impl IntoTokenStream for Result<proc_macro2::TokenStream, Error> { 113b437b383SMiguel Ojeda fn into_ts(self) -> proc_macro2::TokenStream { 114b437b383SMiguel Ojeda match self { 115b437b383SMiguel Ojeda Ok(ts) => ts, 116b437b383SMiguel Ojeda Err(err) => err.to_compile_error(), 117b437b383SMiguel Ojeda } 118b437b383SMiguel Ojeda } 119b437b383SMiguel Ojeda } 120b437b383SMiguel Ojeda 121b437b383SMiguel Ojeda derive!(KnownLayout => derive_known_layout => crate::derive::known_layout::derive); 122b437b383SMiguel Ojeda derive!(Immutable => derive_immutable => crate::derive::derive_immutable); 123b437b383SMiguel Ojeda derive!(TryFromBytes => derive_try_from_bytes => crate::derive::try_from_bytes::derive_try_from_bytes); 124b437b383SMiguel Ojeda derive!(FromZeros => derive_from_zeros => crate::derive::from_bytes::derive_from_zeros); 125b437b383SMiguel Ojeda derive!(FromBytes => derive_from_bytes => crate::derive::from_bytes::derive_from_bytes); 126b437b383SMiguel Ojeda derive!(IntoBytes => derive_into_bytes => crate::derive::into_bytes::derive_into_bytes); 127b437b383SMiguel Ojeda derive!(Unaligned => derive_unaligned => crate::derive::unaligned::derive_unaligned); 128b437b383SMiguel Ojeda derive!(ByteHash => derive_hash => crate::derive::derive_hash); 129b437b383SMiguel Ojeda derive!(ByteEq => derive_eq => crate::derive::derive_eq); 130b437b383SMiguel Ojeda derive!(SplitAt => derive_split_at => crate::derive::derive_split_at); 131b437b383SMiguel Ojeda 132b437b383SMiguel Ojeda /// Deprecated: prefer [`FromZeros`] instead. 133b437b383SMiguel Ojeda #[deprecated(since = "0.8.0", note = "`FromZeroes` was renamed to `FromZeros`")] 134b437b383SMiguel Ojeda #[doc(hidden)] 135b437b383SMiguel Ojeda #[proc_macro_derive(FromZeroes)] 136b437b383SMiguel Ojeda pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { 137b437b383SMiguel Ojeda derive_from_zeros(ts) 138b437b383SMiguel Ojeda } 139b437b383SMiguel Ojeda 140b437b383SMiguel Ojeda /// Deprecated: prefer [`IntoBytes`] instead. 141b437b383SMiguel Ojeda #[deprecated(since = "0.8.0", note = "`AsBytes` was renamed to `IntoBytes`")] 142b437b383SMiguel Ojeda #[doc(hidden)] 143b437b383SMiguel Ojeda #[proc_macro_derive(AsBytes)] 144b437b383SMiguel Ojeda pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { 145b437b383SMiguel Ojeda derive_into_bytes(ts) 146b437b383SMiguel Ojeda } 147