• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::{attr, linker, ty};
2 use proc_macro2::{Span, TokenStream};
3 use quote::quote;
4 use syn::parse::{Parse, ParseStream, Result};
5 use syn::{bracketed, Attribute, Error, Ident, Token, Type, Visibility};
6 
7 struct Declaration {
8     attrs: Vec<Attribute>,
9     vis: Visibility,
10     ident: Ident,
11     ty: Type,
12 }
13 
14 impl Parse for Declaration {
parse(input: ParseStream) -> Result<Self>15     fn parse(input: ParseStream) -> Result<Self> {
16         let attrs = input.call(Attribute::parse_outer)?;
17         let vis: Visibility = input.parse()?;
18         input.parse::<Token![static]>()?;
19         let mut_token: Option<Token![mut]> = input.parse()?;
20         if let Some(mut_token) = mut_token {
21             return Err(Error::new_spanned(
22                 mut_token,
23                 "static mut is not supported by distributed_slice",
24             ));
25         }
26         let ident: Ident = input.parse()?;
27         input.parse::<Token![:]>()?;
28         let ty: Type = input.parse()?;
29 
30         let eq_token: Option<Token![=]> = input.parse()?;
31         if eq_token.is_some() {
32             let content;
33             bracketed!(content in input);
34             content.parse::<Token![..]>()?;
35         }
36 
37         input.parse::<Token![;]>()?;
38 
39         Ok(Declaration {
40             attrs,
41             vis,
42             ident,
43             ty,
44         })
45     }
46 }
47 
expand(input: TokenStream) -> TokenStream48 pub fn expand(input: TokenStream) -> TokenStream {
49     let msg = "distributed_slice is not implemented for this platform";
50     let error = Error::new_spanned(&input, msg);
51     let unsupported_platform = error.to_compile_error();
52 
53     let decl: Declaration = match syn::parse2(input) {
54         Ok(decl) => decl,
55         Err(err) => return err.to_compile_error(),
56     };
57 
58     let mut attrs = decl.attrs;
59     let vis = decl.vis;
60     let ident = decl.ident;
61     let mut ty = decl.ty;
62     let name = ident.to_string();
63 
64     let linkme_path = match attr::linkme_path(&mut attrs) {
65         Ok(path) => path,
66         Err(err) => return err.to_compile_error(),
67     };
68 
69     ty::populate_static_lifetimes(&mut ty);
70 
71     let used = if cfg!(feature = "used_linker") {
72         quote!(#[used(linker)])
73     } else {
74         quote!(#[used])
75     };
76 
77     let linux_section = linker::linux::section(&ident);
78     let linux_section_start = linker::linux::section_start(&ident);
79     let linux_section_stop = linker::linux::section_stop(&ident);
80     let linux_dupcheck = linux_section.replacen("linkme", "linkm2", 1);
81     let linux_dupcheck_start = linux_section_start.replacen("linkme", "linkm2", 1);
82     let linux_dupcheck_stop = linux_section_stop.replacen("linkme", "linkm2", 1);
83 
84     let macho_section = linker::macho::section(&ident);
85     let macho_section_start = linker::macho::section_start(&ident);
86     let macho_section_stop = linker::macho::section_stop(&ident);
87     let macho_dupcheck = macho_section.replacen("linkme", "linkm2", 1);
88     let macho_dupcheck_start = macho_section_start.replacen("linkme", "linkm2", 1);
89     let macho_dupcheck_stop = macho_section_stop.replacen("linkme", "linkm2", 1);
90 
91     let windows_section = linker::windows::section(&ident);
92     let windows_section_start = linker::windows::section_start(&ident);
93     let windows_section_stop = linker::windows::section_stop(&ident);
94     let windows_dupcheck = windows_section.replacen("linkme", "linkm2", 1);
95     let windows_dupcheck_start = windows_section_start.replacen("linkme", "linkm2", 1);
96     let windows_dupcheck_stop = windows_section_stop.replacen("linkme", "linkm2", 1);
97 
98     let illumos_section = linker::illumos::section(&ident);
99     let illumos_section_start = linker::illumos::section_start(&ident);
100     let illumos_section_stop = linker::illumos::section_stop(&ident);
101     let illumos_dupcheck = illumos_section.replacen("linkme", "linkm2", 1);
102     let illumos_dupcheck_start = illumos_section_start.replacen("linkme", "linkm2", 1);
103     let illumos_dupcheck_stop = illumos_section_stop.replacen("linkme", "linkm2", 1);
104 
105     let bsd_section = linker::bsd::section(&ident);
106     let bsd_section_start = linker::bsd::section_start(&ident);
107     let bsd_section_stop = linker::bsd::section_stop(&ident);
108     let bsd_dupcheck = bsd_section.replacen("linkme", "linkm2", 1);
109     let bsd_dupcheck_start = bsd_section_start.replacen("linkme", "linkm2", 1);
110     let bsd_dupcheck_stop = bsd_section_stop.replacen("linkme", "linkm2", 1);
111 
112     let call_site = Span::call_site();
113     let link_section_macro_str = format!("_linkme_macro_{}", ident);
114     let link_section_macro = Ident::new(&link_section_macro_str, call_site);
115 
116     let unsafe_extern = if cfg!(no_unsafe_extern_blocks) {
117         None
118     } else {
119         Some(Token![unsafe](call_site))
120     };
121 
122     let (unsafe_attr, link_section_attr) = if cfg!(no_unsafe_attributes) {
123         // #[cfg_attr(all(), link_section = ...)]
124         (
125             Ident::new("cfg_attr", call_site),
126             quote!(all(), link_section),
127         )
128     } else {
129         // #[unsafe(link_section = ...)]
130         (Ident::new("unsafe", call_site), quote!(link_section))
131     };
132 
133     quote! {
134         #(#attrs)*
135         #vis static #ident: #linkme_path::DistributedSlice<#ty> = {
136             #[cfg(any(
137                 target_os = "none",
138                 target_os = "linux",
139                 target_os = "macos",
140                 target_os = "ios",
141                 target_os = "tvos",
142                 target_os = "android",
143                 target_os = "fuchsia",
144                 target_os = "illumos",
145                 target_os = "freebsd",
146                 target_os = "openbsd",
147                 target_os = "psp",
148             ))]
149             #unsafe_extern extern "Rust" {
150                 #[cfg_attr(any(target_os = "none", target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "psp"), link_name = #linux_section_start)]
151                 #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_section_start)]
152                 #[cfg_attr(target_os = "illumos", link_name = #illumos_section_start)]
153                 #[cfg_attr(any(target_os = "freebsd", target_os = "openbsd"), link_name = #bsd_section_start)]
154                 static LINKME_START: <#ty as #linkme_path::__private::Slice>::Element;
155 
156                 #[cfg_attr(any(target_os = "none", target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "psp"), link_name = #linux_section_stop)]
157                 #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_section_stop)]
158                 #[cfg_attr(target_os = "illumos", link_name = #illumos_section_stop)]
159                 #[cfg_attr(any(target_os = "freebsd", target_os = "openbsd"), link_name = #bsd_section_stop)]
160                 static LINKME_STOP: <#ty as #linkme_path::__private::Slice>::Element;
161 
162                 #[cfg_attr(any(target_os = "none", target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "psp"), link_name = #linux_dupcheck_start)]
163                 #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_dupcheck_start)]
164                 #[cfg_attr(target_os = "illumos", link_name = #illumos_dupcheck_start)]
165                 #[cfg_attr(any(target_os = "freebsd", target_os = "openbsd"), link_name = #bsd_dupcheck_start)]
166                 static DUPCHECK_START: #linkme_path::__private::usize;
167 
168                 #[cfg_attr(any(target_os = "none", target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "psp"), link_name = #linux_dupcheck_stop)]
169                 #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_dupcheck_stop)]
170                 #[cfg_attr(target_os = "illumos", link_name = #illumos_dupcheck_stop)]
171                 #[cfg_attr(any(target_os = "freebsd", target_os = "openbsd"), link_name = #bsd_dupcheck_stop)]
172                 static DUPCHECK_STOP: #linkme_path::__private::usize;
173             }
174 
175             #[cfg(any(target_os = "uefi", target_os = "windows"))]
176             #[#unsafe_attr(#link_section_attr = #windows_section_start)]
177             static LINKME_START: [<#ty as #linkme_path::__private::Slice>::Element; 0] = [];
178 
179             #[cfg(any(target_os = "uefi", target_os = "windows"))]
180             #[#unsafe_attr(#link_section_attr = #windows_section_stop)]
181             static LINKME_STOP: [<#ty as #linkme_path::__private::Slice>::Element; 0] = [];
182 
183             #[cfg(any(target_os = "uefi", target_os = "windows"))]
184             #[#unsafe_attr(#link_section_attr = #windows_dupcheck_start)]
185             static DUPCHECK_START: () = ();
186 
187             #[cfg(any(target_os = "uefi", target_os = "windows"))]
188             #[#unsafe_attr(#link_section_attr = #windows_dupcheck_stop)]
189             static DUPCHECK_STOP: () = ();
190 
191             #used
192             #[cfg(any(
193                 target_os = "none",
194                 target_os = "linux",
195                 target_os = "android",
196                 target_os = "fuchsia",
197                 target_os = "illumos",
198                 target_os = "freebsd",
199                 target_os = "openbsd",
200                 target_os = "psp",
201             ))]
202             #[cfg_attr(any(target_os = "none", target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "psp"), #unsafe_attr(#link_section_attr = #linux_section))]
203             #[cfg_attr(target_os = "illumos", #unsafe_attr(#link_section_attr = #illumos_section))]
204             #[cfg_attr(any(target_os = "freebsd", target_os = "openbsd"), #unsafe_attr(#link_section_attr = #bsd_section))]
205             static mut LINKME_PLEASE: [<#ty as #linkme_path::__private::Slice>::Element; 0] = [];
206 
207             #used
208             #[cfg_attr(any(target_os = "none", target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "psp"), #unsafe_attr(#link_section_attr = #linux_dupcheck))]
209             #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), #unsafe_attr(#link_section_attr = #macho_dupcheck))]
210             #[cfg_attr(any(target_os = "uefi", target_os = "windows"), #unsafe_attr(#link_section_attr = #windows_dupcheck))]
211             #[cfg_attr(target_os = "illumos", #unsafe_attr(#link_section_attr = #illumos_dupcheck))]
212             #[cfg_attr(any(target_os = "freebsd", target_os = "openbsd"), #unsafe_attr(#link_section_attr = #bsd_dupcheck))]
213             static DUPCHECK: #linkme_path::__private::usize = 1;
214 
215             #[cfg(not(any(
216                 target_os = "none",
217                 target_os = "linux",
218                 target_os = "macos",
219                 target_os = "ios",
220                 target_os = "tvos",
221                 target_os = "windows",
222                 target_os = "uefi",
223                 target_os = "android",
224                 target_os = "fuchsia",
225                 target_os = "illumos",
226                 target_os = "freebsd",
227                 target_os = "openbsd",
228                 target_os = "psp",
229             )))]
230             #unsupported_platform
231 
232             #linkme_path::__private::assert!(
233                 #linkme_path::__private::mem::size_of::<<#ty as #linkme_path::__private::Slice>::Element>() > 0,
234             );
235 
236             unsafe {
237                 #linkme_path::DistributedSlice::private_new(
238                     #name,
239                     #linkme_path::__private::ptr::addr_of!(LINKME_START),
240                     #linkme_path::__private::ptr::addr_of!(LINKME_STOP),
241                     #linkme_path::__private::ptr::addr_of!(DUPCHECK_START),
242                     #linkme_path::__private::ptr::addr_of!(DUPCHECK_STOP),
243                 )
244             }
245         };
246 
247         #[doc(hidden)]
248         #[macro_export]
249         macro_rules! #link_section_macro {
250             (
251                 #![linkme_macro = $macro:path]
252                 #![linkme_sort_key = $key:tt]
253                 $item:item
254             ) => {
255                 $macro ! {
256                     #![linkme_linux_section = concat!(#linux_section, $key)]
257                     #![linkme_macho_section = concat!(#macho_section, $key)]
258                     #![linkme_windows_section = concat!(#windows_section, $key)]
259                     #![linkme_illumos_section = concat!(#illumos_section, $key)]
260                     #![linkme_bsd_section = concat!(#bsd_section, $key)]
261                     $item
262                 }
263             };
264             (
265                 #![linkme_linux_section = $linux_section:expr]
266                 #![linkme_macho_section = $macho_section:expr]
267                 #![linkme_windows_section = $windows_section:expr]
268                 #![linkme_illumos_section = $illumos_section:expr]
269                 #![linkme_bsd_section = $bsd_section:expr]
270                 $item:item
271             ) => {
272                 #used
273                 #[cfg_attr(any(target_os = "none", target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "psp"), #unsafe_attr(#link_section_attr = $linux_section))]
274                 #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), #unsafe_attr(#link_section_attr = $macho_section))]
275                 #[cfg_attr(any(target_os = "uefi", target_os = "windows"), #unsafe_attr(#link_section_attr = $windows_section))]
276                 #[cfg_attr(target_os = "illumos", #unsafe_attr(#link_section_attr = $illumos_section))]
277                 #[cfg_attr(any(target_os = "freebsd", target_os = "openbsd"), #unsafe_attr(#link_section_attr = $bsd_section))]
278                 $item
279             };
280             ($item:item) => {
281                 #used
282                 #[cfg_attr(any(target_os = "none", target_os = "linux", target_os = "android", target_os = "fuchsia", target_os = "psp"), #unsafe_attr(#link_section_attr = #linux_section))]
283                 #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), #unsafe_attr(#link_section_attr = #macho_section))]
284                 #[cfg_attr(any(target_os = "uefi", target_os = "windows"), #unsafe_attr(#link_section_attr = #windows_section))]
285                 #[cfg_attr(target_os = "illumos", #unsafe_attr(#link_section_attr = #illumos_section))]
286                 #[cfg_attr(any(target_os = "freebsd", target_os = "openbsd"), #unsafe_attr(#link_section_attr = #bsd_section))]
287                 $item
288             };
289         }
290 
291         #[doc(hidden)]
292         #vis use #link_section_macro as #ident;
293     }
294 }
295