about summary refs log tree commit diff
path: root/compiler/rustc_metadata/src
diff options
context:
space:
mode:
authorLuqman Aden <me@luqman.ca>2021-03-24 21:45:09 -0700
committerLuqman Aden <me@luqman.ca>2021-05-05 16:04:25 -0700
commitdb555e1284dd37f4f3c76474aabfca09140a7ab3 (patch)
tree6e6e96a1c43ac0c193e3ab756bcfe8d4747c904c /compiler/rustc_metadata/src
parentbacf770f2983a52f31e3537db5f0fe1ef2eaa874 (diff)
downloadrust-db555e1284dd37f4f3c76474aabfca09140a7ab3.tar.gz
rust-db555e1284dd37f4f3c76474aabfca09140a7ab3.zip
Implement RFC 2951: Native link modifiers
This commit implements both the native linking modifiers infrastructure
as well as an initial attempt at the individual modifiers from the RFC.
It also introduces a feature flag for the general syntax along with
individual feature flags for each modifier.
Diffstat (limited to 'compiler/rustc_metadata/src')
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs122
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs11
2 files changed, 104 insertions, 29 deletions
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 523e016eeb9..bc342119efb 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -8,8 +8,8 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Session;
-use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
 crate fn collect(tcx: TyCtxt<'_>) -> Vec<NativeLib> {
@@ -56,6 +56,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
                 cfg: None,
                 foreign_module: Some(it.def_id.to_def_id()),
                 wasm_import_module: None,
+                verbatim: None,
             };
             let mut kind_specified = false;
 
@@ -67,10 +68,18 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
                         None => continue, // skip like historical compilers
                     };
                     lib.kind = match &*kind.as_str() {
-                        "static" => NativeLibKind::StaticBundle,
-                        "static-nobundle" => NativeLibKind::StaticNoBundle,
-                        "dylib" => NativeLibKind::Dylib,
-                        "framework" => NativeLibKind::Framework,
+                        "static" => NativeLibKind::Static { bundle: None, whole_archive: None },
+                        "static-nobundle" => {
+                            sess.struct_span_warn(
+                                item.span(),
+                                "library kind `static-nobundle` has been superseded by specifying \
+                                modifier `-bundle` with library kind `static`",
+                            )
+                            .emit();
+                            NativeLibKind::Static { bundle: Some(false), whole_archive: None }
+                        }
+                        "dylib" => NativeLibKind::Dylib { as_needed: None },
+                        "framework" => NativeLibKind::Framework { as_needed: None },
                         "raw-dylib" => NativeLibKind::RawDylib,
                         k => {
                             struct_span_err!(sess, item.span(), E0458, "unknown kind: `{}`", k)
@@ -108,6 +117,71 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
                 }
             }
 
+            // Do this outside the above loop so we don't depend on modifiers coming
+            // after kinds
+            if let Some(item) = items.iter().find(|item| item.has_name(sym::modifiers)) {
+                if let Some(modifiers) = item.value_str() {
+                    let span = item.name_value_literal_span().unwrap();
+                    for modifier in modifiers.as_str().split(',') {
+                        let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) {
+                            Some(m) => (m, modifier.starts_with('+')),
+                            None => {
+                                sess.span_err(
+                                    span,
+                                    "invalid linking modifier syntax, expected '+' or '-' prefix \
+                                    before one of: bundle, verbatim, whole-archive, as-needed",
+                                );
+                                continue;
+                            }
+                        };
+
+                        match (modifier, &mut lib.kind) {
+                            ("bundle", NativeLibKind::Static { bundle, .. }) => {
+                                *bundle = Some(value);
+                            }
+                            ("bundle", _) => sess.span_err(
+                                span,
+                                "bundle linking modifier is only compatible with \
+                                `static` linking kind",
+                            ),
+
+                            ("verbatim", _) => lib.verbatim = Some(value),
+
+                            ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
+                                *whole_archive = Some(value);
+                            }
+                            ("whole-archive", _) => sess.span_err(
+                                span,
+                                "whole-archive linking modifier is only compatible with \
+                                `static` linking kind",
+                            ),
+
+                            ("as-needed", NativeLibKind::Dylib { as_needed })
+                            | ("as-needed", NativeLibKind::Framework { as_needed }) => {
+                                *as_needed = Some(value);
+                            }
+                            ("as-needed", _) => sess.span_err(
+                                span,
+                                "as-needed linking modifier is only compatible with \
+                                `dylib` and `framework` linking kinds",
+                            ),
+
+                            _ => sess.span_err(
+                                span,
+                                &format!(
+                                    "unrecognized linking modifier `{}`, expected one \
+                                    of: bundle, verbatim, whole-archive, as-needed",
+                                    modifier
+                                ),
+                            ),
+                        }
+                    }
+                } else {
+                    let msg = "must be of the form `#[link(modifiers = \"...\")]`";
+                    sess.span_err(item.span(), msg);
+                }
+            }
+
             // In general we require #[link(name = "...")] but we allow
             // #[link(wasm_import_module = "...")] without the `name`.
             let requires_name = kind_specified || lib.wasm_import_module.is_none();
@@ -152,7 +226,7 @@ impl Collector<'tcx> {
             return;
         }
         let is_osx = self.tcx.sess.target.is_like_osx;
-        if lib.kind == NativeLibKind::Framework && !is_osx {
+        if matches!(lib.kind, NativeLibKind::Framework { .. }) && !is_osx {
             let msg = "native frameworks are only available on macOS targets";
             match span {
                 Some(span) => struct_span_err!(self.tcx.sess, span, E0455, "{}", msg).emit(),
@@ -168,7 +242,9 @@ impl Collector<'tcx> {
             )
             .emit();
         }
-        if lib.kind == NativeLibKind::StaticNoBundle && !self.tcx.features().static_nobundle {
+        if matches!(lib.kind, NativeLibKind::Static { bundle: Some(false), .. })
+            && !self.tcx.features().static_nobundle
+        {
             feature_err(
                 &self.tcx.sess.parse_sess,
                 sym::static_nobundle,
@@ -193,30 +269,30 @@ impl Collector<'tcx> {
     fn process_command_line(&mut self) {
         // First, check for errors
         let mut renames = FxHashSet::default();
-        for (name, new_name, _) in &self.tcx.sess.opts.libs {
-            if let Some(ref new_name) = new_name {
+        for lib in &self.tcx.sess.opts.libs {
+            if let Some(ref new_name) = lib.new_name {
                 let any_duplicate = self
                     .libs
                     .iter()
                     .filter_map(|lib| lib.name.as_ref())
-                    .any(|n| &n.as_str() == name);
+                    .any(|n| &n.as_str() == &lib.name);
                 if new_name.is_empty() {
                     self.tcx.sess.err(&format!(
                         "an empty renaming target was specified for library `{}`",
-                        name
+                        lib.name
                     ));
                 } else if !any_duplicate {
                     self.tcx.sess.err(&format!(
                         "renaming of the library `{}` was specified, \
                                                 however this crate contains no `#[link(...)]` \
                                                 attributes referencing this library.",
-                        name
+                        lib.name
                     ));
-                } else if !renames.insert(name) {
+                } else if !renames.insert(&lib.name) {
                     self.tcx.sess.err(&format!(
                         "multiple renamings were \
                                                 specified for library `{}` .",
-                        name
+                        lib.name
                     ));
                 }
             }
@@ -229,7 +305,7 @@ impl Collector<'tcx> {
         // it.  (This ensures that the linker is able to see symbols from
         // all possible dependent libraries before linking in the library
         // in question.)
-        for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs {
+        for passed_lib in &self.tcx.sess.opts.libs {
             // If we've already added any native libraries with the same
             // name, they will be pulled out into `existing`, so that we
             // can move them to the end of the list below.
@@ -237,13 +313,14 @@ impl Collector<'tcx> {
                 .libs
                 .drain_filter(|lib| {
                     if let Some(lib_name) = lib.name {
-                        if lib_name.as_str() == *name {
-                            if kind != NativeLibKind::Unspecified {
-                                lib.kind = kind;
+                        if lib_name.as_str() == passed_lib.name {
+                            if passed_lib.kind != NativeLibKind::Unspecified {
+                                lib.kind = passed_lib.kind;
                             }
-                            if let Some(new_name) = new_name {
+                            if let Some(new_name) = &passed_lib.new_name {
                                 lib.name = Some(Symbol::intern(new_name));
                             }
+                            lib.verbatim = passed_lib.verbatim;
                             return true;
                         }
                     }
@@ -252,13 +329,14 @@ impl Collector<'tcx> {
                 .collect::<Vec<_>>();
             if existing.is_empty() {
                 // Add if not found
-                let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
+                let new_name = passed_lib.new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
                 let lib = NativeLib {
-                    name: Some(Symbol::intern(new_name.unwrap_or(name))),
-                    kind,
+                    name: Some(Symbol::intern(new_name.unwrap_or(&passed_lib.name))),
+                    kind: passed_lib.kind,
                     cfg: None,
                     foreign_module: None,
                     wasm_import_module: None,
+                    verbatim: passed_lib.verbatim,
                 };
                 self.register_native_lib(None, lib);
             } else {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 8595a70dd94..b11ad6c7ff8 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -256,16 +256,13 @@ pub fn provide(providers: &mut Providers) {
     // resolve! Does this work? Unsure! That's what the issue is about
     *providers = Providers {
         is_dllimport_foreign_item: |tcx, id| match tcx.native_library_kind(id) {
-            Some(NativeLibKind::Dylib | NativeLibKind::RawDylib | NativeLibKind::Unspecified) => {
-                true
-            }
+            Some(
+                NativeLibKind::Dylib { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified,
+            ) => true,
             _ => false,
         },
         is_statically_included_foreign_item: |tcx, id| {
-            matches!(
-                tcx.native_library_kind(id),
-                Some(NativeLibKind::StaticBundle | NativeLibKind::StaticNoBundle)
-            )
+            matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. }))
         },
         native_library_kind: |tcx, id| {
             tcx.native_libraries(id.krate)