1use crate::{attr, linker, ty};
2use proc_macro2::{Span, TokenStream};
3use quote::quote;
4use syn::parse::{Parse, ParseStream, Result};
5use syn::{bracketed, Attribute, Error, Ident, Token, Type, Visibility};
6
7struct Declaration {
8 attrs: Vec<Attribute>,
9 vis: Visibility,
10 ident: Ident,
11 ty: Type,
12}
13
14impl Parse for Declaration {
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
48pub 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)
120 };
121
122 let (unsafe_attr, link_section_attr) = if cfg!(no_unsafe_attributes) {
123 (
125 Ident::new("cfg_attr", call_site),
126 quote!(all(), link_section),
127 )
128 } else {
129 (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}