diff options
author | Andrew Walbran <qwandor@google.com> | 2023-06-01 21:35:03 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-06-01 21:35:03 +0000 |
commit | e865b91d2c5ba1ac8ef6fad8b09840c7c86666c7 (patch) | |
tree | cd28798ac383620be052e5394e2e0fbaea4a5a62 | |
parent | 62404015ee301bd9a3a957ddcd7c8f1a24507134 (diff) | |
parent | 932f44c63d471f32ab7370d9e94510cc0bb50a64 (diff) | |
download | linkme-impl-e865b91d2c5ba1ac8ef6fad8b09840c7c86666c7.tar.gz |
Initial import am: 2bee81a675 am: d918ea90ce am: f8a943cdca am: e14bd4aa7a am: 8c465ee650 am: 932f44c63d
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/linkme-impl/+/2608747
Change-Id: I8c5d31c667af6845eec9ff432566543f6d661074
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | .cargo_vcs_info.json | 6 | ||||
-rw-r--r-- | Android.bp | 20 | ||||
-rw-r--r-- | Cargo.toml | 39 | ||||
-rw-r--r-- | Cargo.toml.orig | 24 | ||||
-rw-r--r-- | LICENSE | 176 | ||||
-rw-r--r-- | LICENSE-APACHE | 176 | ||||
-rw-r--r-- | LICENSE-MIT | 23 | ||||
-rw-r--r-- | METADATA | 20 | ||||
-rw-r--r-- | MODULE_LICENSE_APACHE2 | 0 | ||||
-rw-r--r-- | OWNERS | 1 | ||||
-rw-r--r-- | cargo2android.json | 6 | ||||
-rw-r--r-- | src/args.rs | 27 | ||||
-rw-r--r-- | src/attr.rs | 37 | ||||
-rw-r--r-- | src/declaration.rs | 300 | ||||
-rw-r--r-- | src/element.rs | 241 | ||||
-rw-r--r-- | src/hash.rs | 42 | ||||
-rw-r--r-- | src/lib.rs | 32 | ||||
-rw-r--r-- | src/linker.rs | 82 |
18 files changed, 1252 insertions, 0 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json new file mode 100644 index 0000000..a449620 --- /dev/null +++ b/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "a0c3cdd977aefdf6674754ca8b1dc4aa41a7f0ae" + }, + "path_in_vcs": "impl" +}
\ No newline at end of file diff --git a/Android.bp b/Android.bp new file mode 100644 index 0000000..b7b8d0d --- /dev/null +++ b/Android.bp @@ -0,0 +1,20 @@ +// This file is generated by cargo2android.py --config cargo2android.json. +// Do not modify this file as changes will be overridden on upgrade. + + + +rust_proc_macro { + name: "liblinkme_impl", + crate_name: "linkme_impl", + cargo_env_compat: true, + cargo_pkg_version: "0.3.9", + srcs: ["src/lib.rs"], + edition: "2021", + rustlibs: [ + "libproc_macro2", + "libquote", + "libsyn", + ], + product_available: true, + vendor_available: true, +} diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..90491a7 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,39 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.62" +name = "linkme-impl" +version = "0.3.9" +authors = ["David Tolnay <dtolnay@gmail.com>"] +description = "Implementation detail of the linkme crate" +documentation = "https://docs.rs/linkme" +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/linkme" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[lib] +proc-macro = true + +[dependencies.proc-macro2] +version = "1.0.2" + +[dependencies.quote] +version = "1.0" + +[dependencies.syn] +version = "2.0" + +[features] +used_linker = [] diff --git a/Cargo.toml.orig b/Cargo.toml.orig new file mode 100644 index 0000000..694b1c2 --- /dev/null +++ b/Cargo.toml.orig @@ -0,0 +1,24 @@ +[package] +name = "linkme-impl" +version = "0.3.9" +authors = ["David Tolnay <dtolnay@gmail.com>"] +description = "Implementation detail of the linkme crate" +documentation = "https://docs.rs/linkme" +edition = "2021" +license = "MIT OR Apache-2.0" +repository = "https://github.com/dtolnay/linkme" +rust-version = "1.62" + +[lib] +proc-macro = true + +[features] +used_linker = [] + +[dependencies] +proc-macro2 = "1.0.2" +quote = "1.0" +syn = "2.0" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/METADATA b/METADATA new file mode 100644 index 0000000..f2c68f8 --- /dev/null +++ b/METADATA @@ -0,0 +1,20 @@ +name: "linkme-impl" +description: "Safe cross-platform linker shenanigans" +third_party { + url { + type: HOMEPAGE + value: "https://crates.io/crates/linkme-impl" + } + url { + type: ARCHIVE + value: "https://static.crates.io/crates/linkme/linkme-impl-0.3.9.crate" + } + version: "0.3.9" + # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same. + license_type: NOTICE + last_upgrade_date { + year: 2023 + month: 5 + day: 9 + } +} diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_APACHE2 @@ -0,0 +1 @@ +include platform/prebuilts/rust:master:/OWNERS diff --git a/cargo2android.json b/cargo2android.json new file mode 100644 index 0000000..3224ff7 --- /dev/null +++ b/cargo2android.json @@ -0,0 +1,6 @@ +{ + "dependencies": true, + "device": true, + "run": true, + "test": true +}
\ No newline at end of file diff --git a/src/args.rs b/src/args.rs new file mode 100644 index 0000000..cdb2bfc --- /dev/null +++ b/src/args.rs @@ -0,0 +1,27 @@ +use syn::parse::{Error, Parse, ParseStream, Result}; +use syn::{LitInt, Path, Token}; + +pub enum Args { + None, + Path(Path), + PathPos(Path, usize), +} + +impl Parse for Args { + fn parse(input: ParseStream) -> Result<Self> { + if input.is_empty() { + return Ok(Args::None); + } + let path: Path = input.parse()?; + if input.is_empty() { + return Ok(Args::Path(path)); + } + input.parse::<Token![,]>()?; + let lit: LitInt = input.parse()?; + let pos: usize = lit.base10_parse()?; + if pos > 9999 { + return Err(Error::new(lit.span(), "maximum 9999 is supported")); + } + Ok(Args::PathPos(path, pos)) + } +} diff --git a/src/attr.rs b/src/attr.rs new file mode 100644 index 0000000..dca1511 --- /dev/null +++ b/src/attr.rs @@ -0,0 +1,37 @@ +use syn::parse::{Error, Result}; +use syn::{parse_quote, Attribute, Path}; + +// #[linkme(crate = path::to::linkme)] +pub(crate) fn linkme_path(attrs: &mut Vec<Attribute>) -> Result<Path> { + let mut linkme_path = None; + let mut errors: Option<Error> = None; + + attrs.retain(|attr| { + if !attr.path().is_ident("linkme") { + return true; + } + if let Err(err) = attr.parse_nested_meta(|meta| { + if meta.path.is_ident("crate") { + if linkme_path.is_some() { + return Err(meta.error("duplicate linkme crate attribute")); + } + let path = meta.value()?.call(Path::parse_mod_style)?; + linkme_path = Some(path); + Ok(()) + } else { + Err(meta.error("unsupported linkme attribute")) + } + }) { + match &mut errors { + None => errors = Some(err), + Some(errors) => errors.combine(err), + } + } + false + }); + + match errors { + None => Ok(linkme_path.unwrap_or_else(|| parse_quote!(::linkme))), + Some(errors) => Err(errors), + } +} diff --git a/src/declaration.rs b/src/declaration.rs new file mode 100644 index 0000000..7543bad --- /dev/null +++ b/src/declaration.rs @@ -0,0 +1,300 @@ +use crate::{attr, linker}; +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use syn::parse::{Parse, ParseStream, Result}; +use syn::{ + bracketed, Attribute, Error, GenericArgument, Ident, Lifetime, PathArguments, Token, Type, + Visibility, +}; + +struct Declaration { + attrs: Vec<Attribute>, + vis: Visibility, + ident: Ident, + ty: Type, +} + +impl Parse for Declaration { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let vis: Visibility = input.parse()?; + input.parse::<Token![static]>()?; + let mut_token: Option<Token![mut]> = input.parse()?; + if let Some(mut_token) = mut_token { + return Err(Error::new_spanned( + mut_token, + "static mut is not supported by distributed_slice", + )); + } + let ident: Ident = input.parse()?; + input.parse::<Token![:]>()?; + let ty: Type = input.parse()?; + input.parse::<Token![=]>()?; + + let content; + bracketed!(content in input); + content.parse::<Token![..]>()?; + + input.parse::<Token![;]>()?; + + Ok(Declaration { + attrs, + vis, + ident, + ty, + }) + } +} + +pub fn expand(input: TokenStream) -> TokenStream { + let msg = "distributed_slice is not implemented for this platform"; + let error = Error::new_spanned(&input, msg); + let unsupported_platform = error.to_compile_error(); + + let decl: Declaration = match syn::parse2(input) { + Ok(decl) => decl, + Err(err) => return err.to_compile_error(), + }; + + let mut attrs = decl.attrs; + let vis = decl.vis; + let ident = decl.ident; + let mut ty = decl.ty; + let name = ident.to_string(); + + let linkme_path = match attr::linkme_path(&mut attrs) { + Ok(path) => path, + Err(err) => return err.to_compile_error(), + }; + + populate_static_lifetimes(&mut ty); + + let used = if cfg!(feature = "used_linker") { + quote!(#[used(linker)]) + } else { + quote!(#[used]) + }; + + let linux_section = linker::linux::section(&ident); + let linux_section_start = linker::linux::section_start(&ident); + let linux_section_stop = linker::linux::section_stop(&ident); + let linux_dupcheck = linux_section.replacen("linkme", "linkm2", 1); + let linux_dupcheck_start = linux_section_start.replacen("linkme", "linkm2", 1); + let linux_dupcheck_stop = linux_section_stop.replacen("linkme", "linkm2", 1); + + let macho_section = linker::macho::section(&ident); + let macho_section_start = linker::macho::section_start(&ident); + let macho_section_stop = linker::macho::section_stop(&ident); + let macho_dupcheck = macho_section.replacen("linkme", "linkm2", 1); + let macho_dupcheck_start = macho_section_start.replacen("linkme", "linkm2", 1); + let macho_dupcheck_stop = macho_section_stop.replacen("linkme", "linkm2", 1); + + let windows_section = linker::windows::section(&ident); + let windows_section_start = linker::windows::section_start(&ident); + let windows_section_stop = linker::windows::section_stop(&ident); + let windows_dupcheck = windows_section.replacen("linkme", "linkm2", 1); + let windows_dupcheck_start = windows_section_start.replacen("linkme", "linkm2", 1); + let windows_dupcheck_stop = windows_section_stop.replacen("linkme", "linkm2", 1); + + let illumos_section = linker::illumos::section(&ident); + let illumos_section_start = linker::illumos::section_start(&ident); + let illumos_section_stop = linker::illumos::section_stop(&ident); + let illumos_dupcheck = illumos_section.replacen("linkme", "linkm2", 1); + let illumos_dupcheck_start = illumos_section_start.replacen("linkme", "linkm2", 1); + let illumos_dupcheck_stop = illumos_section_stop.replacen("linkme", "linkm2", 1); + + let freebsd_section = linker::freebsd::section(&ident); + let freebsd_section_start = linker::freebsd::section_start(&ident); + let freebsd_section_stop = linker::freebsd::section_stop(&ident); + let freebsd_dupcheck = freebsd_section.replacen("linkme", "linkm2", 1); + let freebsd_dupcheck_start = freebsd_section_start.replacen("linkme", "linkm2", 1); + let freebsd_dupcheck_stop = freebsd_section_stop.replacen("linkme", "linkm2", 1); + + let call_site = Span::call_site(); + let link_section_macro_str = format!("_linkme_macro_{}", ident); + let link_section_macro = Ident::new(&link_section_macro_str, call_site); + + quote! { + #(#attrs)* + #vis static #ident: #linkme_path::DistributedSlice<#ty> = { + #[cfg(any( + target_os = "none", + target_os = "linux", + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "illumos", + target_os = "freebsd", + ))] + extern "Rust" { + #[cfg_attr(any(target_os = "none", target_os = "linux"), link_name = #linux_section_start)] + #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_section_start)] + #[cfg_attr(target_os = "illumos", link_name = #illumos_section_start)] + #[cfg_attr(target_os = "freebsd", link_name = #freebsd_section_start)] + static LINKME_START: <#ty as #linkme_path::__private::Slice>::Element; + + #[cfg_attr(any(target_os = "none", target_os = "linux"), link_name = #linux_section_stop)] + #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_section_stop)] + #[cfg_attr(target_os = "illumos", link_name = #illumos_section_stop)] + #[cfg_attr(target_os = "freebsd", link_name = #freebsd_section_stop)] + static LINKME_STOP: <#ty as #linkme_path::__private::Slice>::Element; + + #[cfg_attr(any(target_os = "none", target_os = "linux"), link_name = #linux_dupcheck_start)] + #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_dupcheck_start)] + #[cfg_attr(target_os = "illumos", link_name = #illumos_dupcheck_start)] + #[cfg_attr(target_os = "freebsd", link_name = #freebsd_dupcheck_start)] + static DUPCHECK_START: #linkme_path::__private::usize; + + #[cfg_attr(any(target_os = "none", target_os = "linux"), link_name = #linux_dupcheck_stop)] + #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_name = #macho_dupcheck_stop)] + #[cfg_attr(target_os = "illumos", link_name = #illumos_dupcheck_stop)] + #[cfg_attr(target_os = "freebsd", link_name = #freebsd_dupcheck_stop)] + static DUPCHECK_STOP: #linkme_path::__private::usize; + } + + #[cfg(target_os = "windows")] + #[link_section = #windows_section_start] + static LINKME_START: [<#ty as #linkme_path::__private::Slice>::Element; 0] = []; + + #[cfg(target_os = "windows")] + #[link_section = #windows_section_stop] + static LINKME_STOP: [<#ty as #linkme_path::__private::Slice>::Element; 0] = []; + + #[cfg(target_os = "windows")] + #[link_section = #windows_dupcheck_start] + static DUPCHECK_START: () = (); + + #[cfg(target_os = "windows")] + #[link_section = #windows_dupcheck_stop] + static DUPCHECK_STOP: () = (); + + #used + #[cfg(any(target_os = "none", target_os = "linux", target_os = "illumos", target_os = "freebsd"))] + #[cfg_attr(any(target_os = "none", target_os = "linux"), link_section = #linux_section)] + #[cfg_attr(target_os = "illumos", link_section = #illumos_section)] + #[cfg_attr(target_os = "freebsd", link_section = #freebsd_section)] + static mut LINKME_PLEASE: [<#ty as #linkme_path::__private::Slice>::Element; 0] = []; + + #used + #[cfg_attr(any(target_os = "none", target_os = "linux"), link_section = #linux_dupcheck)] + #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_section = #macho_dupcheck)] + #[cfg_attr(target_os = "windows", link_section = #windows_dupcheck)] + #[cfg_attr(target_os = "illumos", link_section = #illumos_dupcheck)] + #[cfg_attr(target_os = "freebsd", link_section = #freebsd_dupcheck)] + static DUPCHECK: #linkme_path::__private::usize = 1; + + #[cfg(not(any( + target_os = "none", + target_os = "linux", + target_os = "macos", + target_os = "ios", + target_os = "tvos", + target_os = "windows", + target_os = "illumos", + target_os = "freebsd", + )))] + #unsupported_platform + + #linkme_path::__private::assert!( + #linkme_path::__private::mem::size_of::<<#ty as #linkme_path::__private::Slice>::Element>() > 0, + ); + + unsafe { + #linkme_path::DistributedSlice::private_new( + #name, + &LINKME_START, + &LINKME_STOP, + &DUPCHECK_START, + &DUPCHECK_STOP, + ) + } + }; + + #[doc(hidden)] + #[macro_export] + macro_rules! #link_section_macro { + ( + #![linkme_macro = $macro:path] + #![linkme_sort_key = $key:tt] + $item:item + ) => { + $macro ! { + #![linkme_linux_section = concat!(#linux_section, $key)] + #![linkme_macho_section = concat!(#macho_section, $key)] + #![linkme_windows_section = concat!(#windows_section, $key)] + #![linkme_illumos_section = concat!(#illumos_section, $key)] + #![linkme_freebsd_section = concat!(#freebsd_section, $key)] + $item + } + }; + ( + #![linkme_linux_section = $linux_section:expr] + #![linkme_macho_section = $macho_section:expr] + #![linkme_windows_section = $windows_section:expr] + #![linkme_illumos_section = $illumos_section:expr] + #![linkme_freebsd_section = $freebsd_section:expr] + $item:item + ) => { + #used + #[cfg_attr(any(target_os = "none", target_os = "linux"), link_section = $linux_section)] + #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_section = $macho_section)] + #[cfg_attr(target_os = "windows", link_section = $windows_section)] + #[cfg_attr(target_os = "illumos", link_section = $illumos_section)] + #[cfg_attr(target_os = "freebsd", link_section = $freebsd_section)] + $item + }; + ($item:item) => { + #used + #[cfg_attr(any(target_os = "none", target_os = "linux"), link_section = #linux_section)] + #[cfg_attr(any(target_os = "macos", target_os = "ios", target_os = "tvos"), link_section = #macho_section)] + #[cfg_attr(target_os = "windows", link_section = #windows_section)] + #[cfg_attr(target_os = "illumos", link_section = #illumos_section)] + #[cfg_attr(target_os = "freebsd", link_section = #freebsd_section)] + $item + }; + } + + #[doc(hidden)] + #vis use #link_section_macro as #ident; + } +} + +fn populate_static_lifetimes(ty: &mut Type) { + match ty { + Type::Array(ty) => populate_static_lifetimes(&mut ty.elem), + Type::Group(ty) => populate_static_lifetimes(&mut ty.elem), + Type::Paren(ty) => populate_static_lifetimes(&mut ty.elem), + Type::Path(ty) => { + if let Some(qself) = &mut ty.qself { + populate_static_lifetimes(&mut qself.ty); + } + for segment in &mut ty.path.segments { + if let PathArguments::AngleBracketed(segment) = &mut segment.arguments { + for arg in &mut segment.args { + if let GenericArgument::Type(arg) = arg { + populate_static_lifetimes(arg); + } + } + } + } + } + Type::Ptr(ty) => populate_static_lifetimes(&mut ty.elem), + Type::Reference(ty) => { + if ty.lifetime.is_none() { + ty.lifetime = Some(Lifetime::new("'static", ty.and_token.span)); + } + populate_static_lifetimes(&mut ty.elem); + } + Type::Slice(ty) => populate_static_lifetimes(&mut ty.elem), + Type::Tuple(ty) => ty.elems.iter_mut().for_each(populate_static_lifetimes), + Type::ImplTrait(_) + | Type::Infer(_) + | Type::Macro(_) + | Type::Never(_) + | Type::TraitObject(_) + | Type::BareFn(_) + | Type::Verbatim(_) => {} + #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] + _ => unimplemented!("unknown Type"), + } +} diff --git a/src/element.rs b/src/element.rs new file mode 100644 index 0000000..7c85e30 --- /dev/null +++ b/src/element.rs @@ -0,0 +1,241 @@ +use crate::attr; +use proc_macro2::{Span, TokenStream, TokenTree}; +use quote::{format_ident, quote, quote_spanned}; +use std::iter::FromIterator; +use syn::parse::{Error, Parse, ParseStream, Result}; +use syn::punctuated::Punctuated; +use syn::{ + braced, parenthesized, parse_quote, Abi, Attribute, BareFnArg, BoundLifetimes, GenericParam, + Generics, Ident, Path, ReturnType, Token, Type, TypeBareFn, Visibility, WhereClause, +}; + +pub struct Element { + attrs: Vec<Attribute>, + vis: Visibility, + ident: Ident, + ty: Type, + expr: TokenStream, + orig_item: Option<TokenStream>, + start_span: Span, + end_span: Span, +} + +impl Parse for Element { + fn parse(input: ParseStream) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + let item = input.cursor(); + let vis: Visibility = input.parse()?; + let static_token: Option<Token![static]> = input.parse()?; + if static_token.is_some() { + let mut_token: Option<Token![mut]> = input.parse()?; + if let Some(mut_token) = mut_token { + return Err(Error::new_spanned( + mut_token, + "static mut is not supported by distributed_slice", + )); + } + let ident: Ident = input.parse()?; + input.parse::<Token![:]>()?; + let start_span = input.span(); + let ty: Type = input.parse()?; + let end_span = quote!(#ty).into_iter().last().unwrap().span(); + input.parse::<Token![=]>()?; + let mut expr_semi = Vec::from_iter(input.parse::<TokenStream>()?); + if let Some(tail) = expr_semi.pop() { + syn::parse2::<Token![;]>(TokenStream::from(tail))?; + } + let expr = TokenStream::from_iter(expr_semi); + Ok(Element { + attrs, + vis, + ident, + ty, + expr, + orig_item: None, + start_span, + end_span, + }) + } else { + let constness: Option<Token![const]> = input.parse()?; + let asyncness: Option<Token![async]> = input.parse()?; + let unsafety: Option<Token![unsafe]> = input.parse()?; + let abi: Option<Abi> = input.parse()?; + let fn_token: Token![fn] = input.parse().map_err(|_| { + Error::new_spanned( + item.token_stream(), + "distributed element must be either static or function item", + ) + })?; + let ident: Ident = input.parse()?; + let generics: Generics = input.parse()?; + + let content; + let paren_token = parenthesized!(content in input); + let mut inputs = Punctuated::new(); + while !content.is_empty() { + content.parse::<Option<Token![mut]>>()?; + let ident = if let Some(wild) = content.parse::<Option<Token![_]>>()? { + Ident::from(wild) + } else { + content.parse()? + }; + let colon_token: Token![:] = content.parse()?; + let ty: Type = content.parse()?; + inputs.push_value(BareFnArg { + attrs: Vec::new(), + name: Some((ident, colon_token)), + ty, + }); + if !content.is_empty() { + let comma: Token![,] = content.parse()?; + inputs.push_punct(comma); + } + } + + let output: ReturnType = input.parse()?; + let where_clause: Option<WhereClause> = input.parse()?; + + let content; + braced!(content in input); + content.parse::<TokenStream>()?; + + if let Some(constness) = constness { + return Err(Error::new_spanned( + constness, + "const fn distributed slice element is not supported", + )); + } + + if let Some(asyncness) = asyncness { + return Err(Error::new_spanned( + asyncness, + "async fn distributed slice element is not supported", + )); + } + + let lifetimes = if generics.params.is_empty() { + None + } else { + let mut bound = BoundLifetimes { + for_token: Token![for](generics.lt_token.unwrap().span), + lt_token: generics.lt_token.unwrap(), + lifetimes: Punctuated::new(), + gt_token: generics.gt_token.unwrap(), + }; + for param in generics.params.into_pairs() { + let (param, punct) = param.into_tuple(); + if let GenericParam::Lifetime(_) = param { + bound.lifetimes.push_value(param); + if let Some(punct) = punct { + bound.lifetimes.push_punct(punct); + } + } else { + return Err(Error::new_spanned( + param, + "cannot have generic parameters on distributed slice element", + )); + } + } + Some(bound) + }; + + if let Some(where_clause) = where_clause { + return Err(Error::new_spanned( + where_clause, + "where-clause is not allowed on distributed slice elements", + )); + } + + let start_span = item.span(); + let end_span = quote!(#output) + .into_iter() + .last() + .as_ref() + .map_or(paren_token.span.close(), TokenTree::span); + let mut original_attrs = attrs; + let linkme_path = attr::linkme_path(&mut original_attrs)?; + + let attrs = vec![ + parse_quote! { + #[allow(non_upper_case_globals)] + }, + parse_quote! { + #[linkme(crate = #linkme_path)] + }, + ]; + let vis = Visibility::Inherited; + let expr = parse_quote!(#ident); + let ty = Type::BareFn(TypeBareFn { + lifetimes, + unsafety, + abi, + fn_token, + paren_token, + inputs, + variadic: None, + output, + }); + let ident = format_ident!("_LINKME_ELEMENT_{}", ident); + let item = item.token_stream(); + let orig_item = Some(quote!( + #(#original_attrs)* + #item + )); + + Ok(Element { + attrs, + vis, + ident, + ty, + expr, + orig_item, + start_span, + end_span, + }) + } + } +} + +pub fn expand(path: Path, pos: impl Into<Option<usize>>, input: Element) -> TokenStream { + let pos = pos.into(); + do_expand(path, pos, input) +} + +fn do_expand(path: Path, pos: Option<usize>, input: Element) -> TokenStream { + let mut attrs = input.attrs; + let vis = input.vis; + let ident = input.ident; + let ty = input.ty; + let expr = input.expr; + let orig_item = input.orig_item; + + let linkme_path = match attr::linkme_path(&mut attrs) { + Ok(path) => path, + Err(err) => return err.to_compile_error(), + }; + + let sort_key = pos.into_iter().map(|pos| format!("{:04}", pos)); + + let new = quote_spanned!(input.start_span=> __new); + let uninit = quote_spanned!(input.end_span=> #new()); + + quote! { + #path ! { + #( + #![linkme_macro = #path] + #![linkme_sort_key = #sort_key] + )* + #(#attrs)* + #vis static #ident : #ty = { + unsafe fn __typecheck(_: #linkme_path::__private::Void) { + let #new = #linkme_path::__private::value::<#ty>; + #linkme_path::DistributedSlice::private_typecheck(#path, #uninit) + } + + #expr + }; + } + + #orig_item + } +} diff --git a/src/hash.rs b/src/hash.rs new file mode 100644 index 0000000..b8e5aea --- /dev/null +++ b/src/hash.rs @@ -0,0 +1,42 @@ +use std::collections::hash_map; +use std::fmt::{self, Display, Write}; +use std::hash::{Hash, Hasher}; +use syn::Ident; + +// 8-character symbol hash consisting of a-zA-Z0-9. We use 8 character because +// Mach-O section specifiers are restricted to at most 16 characters (see +// https://github.com/dtolnay/linkme/issues/35) and we leave room for a +// linkme-specific prefix. +pub(crate) struct Symbol(u64); + +pub(crate) fn hash(ident: &Ident) -> Symbol { + let mut hasher = hash_map::DefaultHasher::new(); + ident.hash(&mut hasher); + Symbol(hasher.finish()) +} + +impl Display for Symbol { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + // log(62^8)/log(2) is 47.6 so we have enough bits in the 64-bit + // standard library hash to produce a good distribution over 8 digits + // from a 62-character alphabet. + let mut remainder = self.0; + for _ in 0..8 { + let digit = (remainder % 62) as u8; + remainder /= 62; + formatter.write_char(match digit { + 0..=25 => b'a' + digit, + 26..=51 => b'A' + digit - 26, + 52..=61 => b'0' + digit - 52, + _ => unreachable!(), + } as char)?; + } + Ok(()) + } +} + +#[test] +fn test_hash() { + let ident = Ident::new("EXAMPLE", proc_macro2::Span::call_site()); + assert_eq!(hash(&ident).to_string(), "0GPSzIoo"); +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..d08aba8 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,32 @@ +#![cfg_attr(all(test, exhaustive), feature(non_exhaustive_omitted_patterns_lint))] +#![allow( + clippy::cast_possible_truncation, // https://github.com/rust-lang/rust-clippy/issues/7486 + clippy::needless_pass_by_value, + clippy::too_many_lines, + clippy::uninlined_format_args, +)] + +mod args; +mod attr; +mod declaration; +mod element; +mod hash; +mod linker; + +use crate::args::Args; +use crate::hash::hash; +use proc_macro::TokenStream; +use syn::parse_macro_input; + +#[proc_macro_attribute] +pub fn distributed_slice(args: TokenStream, input: TokenStream) -> TokenStream { + let args = parse_macro_input!(args as Args); + + let expanded = match args { + Args::None => declaration::expand(parse_macro_input!(input)), + Args::Path(path) => element::expand(path, None, parse_macro_input!(input)), + Args::PathPos(path, pos) => element::expand(path, pos, parse_macro_input!(input)), + }; + + TokenStream::from(expanded) +} diff --git a/src/linker.rs b/src/linker.rs new file mode 100644 index 0000000..75affe2 --- /dev/null +++ b/src/linker.rs @@ -0,0 +1,82 @@ +pub mod linux { + use syn::Ident; + + pub fn section(ident: &Ident) -> String { + format!("linkme_{}", ident) + } + + pub fn section_start(ident: &Ident) -> String { + format!("__start_linkme_{}", ident) + } + + pub fn section_stop(ident: &Ident) -> String { + format!("__stop_linkme_{}", ident) + } +} + +pub mod freebsd { + use syn::Ident; + + pub fn section(ident: &Ident) -> String { + format!("linkme_{}", ident) + } + + pub fn section_start(ident: &Ident) -> String { + format!("__start_linkme_{}", ident) + } + + pub fn section_stop(ident: &Ident) -> String { + format!("__stop_linkme_{}", ident) + } +} + +pub mod macho { + use syn::Ident; + + pub fn section(ident: &Ident) -> String { + format!( + "__DATA,__linkme{},regular,no_dead_strip", + crate::hash(ident), + ) + } + + pub fn section_start(ident: &Ident) -> String { + format!("\x01section$start$__DATA$__linkme{}", crate::hash(ident)) + } + + pub fn section_stop(ident: &Ident) -> String { + format!("\x01section$end$__DATA$__linkme{}", crate::hash(ident)) + } +} + +pub mod windows { + use syn::Ident; + + pub fn section(ident: &Ident) -> String { + format!(".linkme_{}$b", ident) + } + + pub fn section_start(ident: &Ident) -> String { + format!(".linkme_{}$a", ident) + } + + pub fn section_stop(ident: &Ident) -> String { + format!(".linkme_{}$c", ident) + } +} + +pub mod illumos { + use syn::Ident; + + pub fn section(ident: &Ident) -> String { + format!("set_linkme_{}", ident) + } + + pub fn section_start(ident: &Ident) -> String { + format!("__start_set_linkme_{}", ident) + } + + pub fn section_stop(ident: &Ident) -> String { + format!("__stop_set_linkme_{}", ident) + } +} |