From 33cc3f5116e2f1813a54d5038151e0898a670af2 Mon Sep 17 00:00:00 2001 From: Folyd Date: Sun, 18 Apr 2021 19:52:20 +0800 Subject: [PATCH 1/9] Stablize {HashMap,BTreeMap}::into_{keys,values} --- library/alloc/src/collections/btree/map.rs | 30 ++++++++++------------ library/std/src/collections/hash/map.rs | 30 +++++++++------------- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 971244718b4ad..02e2924623c9d 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -398,12 +398,12 @@ impl fmt::Debug for ValuesMut<'_, K, V> { /// See its documentation for more. /// /// [`into_keys`]: BTreeMap::into_keys -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] pub struct IntoKeys { inner: IntoIter, } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl fmt::Debug for IntoKeys { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(key, _)| key)).finish() @@ -416,12 +416,12 @@ impl fmt::Debug for IntoKeys { /// See its documentation for more. /// /// [`into_values`]: BTreeMap::into_values -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] pub struct IntoValues { inner: IntoIter, } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl fmt::Debug for IntoValues { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() @@ -1242,7 +1242,6 @@ impl BTreeMap { /// # Examples /// /// ``` - /// #![feature(map_into_keys_values)] /// use std::collections::BTreeMap; /// /// let mut a = BTreeMap::new(); @@ -1253,7 +1252,7 @@ impl BTreeMap { /// assert_eq!(keys, [1, 2]); /// ``` #[inline] - #[unstable(feature = "map_into_keys_values", issue = "75294")] + #[stable(feature = "map_into_keys_values", since = "1.53.0")] pub fn into_keys(self) -> IntoKeys { IntoKeys { inner: self.into_iter() } } @@ -1265,7 +1264,6 @@ impl BTreeMap { /// # Examples /// /// ``` - /// #![feature(map_into_keys_values)] /// use std::collections::BTreeMap; /// /// let mut a = BTreeMap::new(); @@ -1276,7 +1274,7 @@ impl BTreeMap { /// assert_eq!(values, ["hello", "goodbye"]); /// ``` #[inline] - #[unstable(feature = "map_into_keys_values", issue = "75294")] + #[stable(feature = "map_into_keys_values", since = "1.53.0")] pub fn into_values(self) -> IntoValues { IntoValues { inner: self.into_iter() } } @@ -1776,7 +1774,7 @@ impl<'a, K, V> Range<'a, K, V> { } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl Iterator for IntoKeys { type Item = K; @@ -1801,24 +1799,24 @@ impl Iterator for IntoKeys { } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl DoubleEndedIterator for IntoKeys { fn next_back(&mut self) -> Option { self.inner.next_back().map(|(k, _)| k) } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl ExactSizeIterator for IntoKeys { fn len(&self) -> usize { self.inner.len() } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl FusedIterator for IntoKeys {} -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl Iterator for IntoValues { type Item = V; @@ -1835,21 +1833,21 @@ impl Iterator for IntoValues { } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl DoubleEndedIterator for IntoValues { fn next_back(&mut self) -> Option { self.inner.next_back().map(|(_, v)| v) } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl ExactSizeIterator for IntoValues { fn len(&self) -> usize { self.inner.len() } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl FusedIterator for IntoValues {} #[stable(feature = "btree_range", since = "1.17.0")] diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 3dcc5cd2b5911..32c868fb4ab04 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -962,7 +962,6 @@ where /// # Examples /// /// ``` - /// #![feature(map_into_keys_values)] /// use std::collections::HashMap; /// /// let mut map = HashMap::new(); @@ -973,7 +972,7 @@ where /// let vec: Vec<&str> = map.into_keys().collect(); /// ``` #[inline] - #[unstable(feature = "map_into_keys_values", issue = "75294")] + #[stable(feature = "map_into_keys_values", since = "1.53.0")] pub fn into_keys(self) -> IntoKeys { IntoKeys { inner: self.into_iter() } } @@ -985,7 +984,6 @@ where /// # Examples /// /// ``` - /// #![feature(map_into_keys_values)] /// use std::collections::HashMap; /// /// let mut map = HashMap::new(); @@ -996,7 +994,7 @@ where /// let vec: Vec = map.into_values().collect(); /// ``` #[inline] - #[unstable(feature = "map_into_keys_values", issue = "75294")] + #[stable(feature = "map_into_keys_values", since = "1.53.0")] pub fn into_values(self) -> IntoValues { IntoValues { inner: self.into_iter() } } @@ -1405,15 +1403,13 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { /// # Example /// /// ``` -/// #![feature(map_into_keys_values)] -/// /// use std::collections::HashMap; /// /// let mut map = HashMap::new(); /// map.insert("a", 1); /// let iter_keys = map.into_keys(); /// ``` -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] pub struct IntoKeys { inner: IntoIter, } @@ -1428,15 +1424,13 @@ pub struct IntoKeys { /// # Example /// /// ``` -/// #![feature(map_into_keys_values)] -/// /// use std::collections::HashMap; /// /// let mut map = HashMap::new(); /// map.insert("a", 1); /// let iter_keys = map.into_values(); /// ``` -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] pub struct IntoValues { inner: IntoIter, } @@ -2137,7 +2131,7 @@ impl fmt::Debug for ValuesMut<'_, K, V> { } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl Iterator for IntoKeys { type Item = K; @@ -2150,24 +2144,24 @@ impl Iterator for IntoKeys { self.inner.size_hint() } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl ExactSizeIterator for IntoKeys { #[inline] fn len(&self) -> usize { self.inner.len() } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl FusedIterator for IntoKeys {} -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl fmt::Debug for IntoKeys { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish() } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl Iterator for IntoValues { type Item = V; @@ -2180,17 +2174,17 @@ impl Iterator for IntoValues { self.inner.size_hint() } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl ExactSizeIterator for IntoValues { #[inline] fn len(&self) -> usize { self.inner.len() } } -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl FusedIterator for IntoValues {} -#[unstable(feature = "map_into_keys_values", issue = "75294")] +#[stable(feature = "map_into_keys_values", since = "1.53.0")] impl fmt::Debug for IntoValues { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish() From 8a2e67e0d0826f73531f79ecc8d14aba71a8d837 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 29 Apr 2021 13:11:20 -0700 Subject: [PATCH 2/9] Simplify chdir implementation and minimize unsafe block --- library/std/src/sys/unix/os.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 984c08c2ad531..51c3e5d175cca 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -155,12 +155,10 @@ pub fn getcwd() -> io::Result { pub fn chdir(p: &path::Path) -> io::Result<()> { let p: &OsStr = p.as_ref(); let p = CString::new(p.as_bytes())?; - unsafe { - match libc::chdir(p.as_ptr()) == (0 as c_int) { - true => Ok(()), - false => Err(io::Error::last_os_error()), - } + if unsafe { libc::chdir(p.as_ptr()) } != 0 { + return Err(io::Error::last_os_error()); } + Ok(()) } pub struct SplitPaths<'a> { From 367c1dbd4819fb2148ab35b934b3215abe3af441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 3 May 2021 10:16:06 +0300 Subject: [PATCH 3/9] :arrow_up: rust-analyzer --- src/tools/rust-analyzer | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer index 617535393bb5c..eb741e895f1a7 160000 --- a/src/tools/rust-analyzer +++ b/src/tools/rust-analyzer @@ -1 +1 @@ -Subproject commit 617535393bb5ccc7adf0bac8a3b9a9c306454e79 +Subproject commit eb741e895f1a73420a401f2495c711afe37d9d19 From 4bd5505718696a1ec76e156b91561428468371bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 4 May 2021 11:57:53 -0700 Subject: [PATCH 4/9] Only compute Obligation `cache_key` once in `register_obligation_at` --- .../rustc_data_structures/src/obligation_forest/mod.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index a5b2df1da5d6d..29d685ab530d6 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -336,12 +336,13 @@ impl ObligationForest { // Returns Err(()) if we already know this obligation failed. fn register_obligation_at(&mut self, obligation: O, parent: Option) -> Result<(), ()> { - if self.done_cache.contains(&obligation.as_cache_key()) { + let cache_key = obligation.as_cache_key(); + if self.done_cache.contains(&cache_key) { debug!("register_obligation_at: ignoring already done obligation: {:?}", obligation); return Ok(()); } - match self.active_cache.entry(obligation.as_cache_key()) { + match self.active_cache.entry(cache_key.clone()) { Entry::Occupied(o) => { let node = &mut self.nodes[*o.get()]; if let Some(parent_index) = parent { @@ -365,7 +366,7 @@ impl ObligationForest { && self .error_cache .get(&obligation_tree_id) - .map(|errors| errors.contains(&obligation.as_cache_key())) + .map(|errors| errors.contains(&cache_key)) .unwrap_or(false); if already_failed { From 42405b4fa88d4a422bf26225aea03b7ce50a0ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 5 May 2021 12:31:38 +0300 Subject: [PATCH 5/9] Fix typo in `MaybeUninit::array_assume_init` safety comment And also add backticks around `MaybeUninit`. --- library/core/src/mem/maybe_uninit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index f77acdd618072..10219201a40d3 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -870,7 +870,7 @@ impl MaybeUninit { // SAFETY: // * The caller guarantees that all elements of the array are initialized // * `MaybeUninit` and T are guaranteed to have the same layout - // * MaybeUnint does not drop, so there are no double-frees + // * `MaybeUninit` does not drop, so there are no double-frees // And thus the conversion is safe unsafe { intrinsics::assert_inhabited::<[T; N]>(); From 5b34bf460c68aea356633fd17760a99cc0794f4f Mon Sep 17 00:00:00 2001 From: Pietro Albini Date: Wed, 5 May 2021 11:57:10 +0200 Subject: [PATCH 6/9] Revert PR 83866 That PR caused multiple test failures when Rust's channel is changed from nightly to anything else. The commit will have to be landed again after the test suite is fixed. --- src/librustdoc/clean/types.rs | 7 +++---- src/librustdoc/clean/utils.rs | 11 ----------- src/librustdoc/core.rs | 9 +++------ src/librustdoc/lib.rs | 7 +------ src/librustdoc/passes/collect_intra_doc_links.rs | 9 +-------- .../intra-doc/email-address-localhost.stderr | 1 - .../rustdoc-ui/intra-doc/unknown-disambiguator.stderr | 11 ----------- 7 files changed, 8 insertions(+), 47 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 350742e8f2898..47dae63f1fdf7 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -517,10 +517,9 @@ impl Item { Some(ExternalLocation::Remote(ref s)) => { format!("{}/std/", s.trim_end_matches('/')) } - Some(ExternalLocation::Unknown) | None => format!( - "https://doc.rust-lang.org/{}/std/", - crate::doc_rust_lang_org_channel(), - ), + Some(ExternalLocation::Unknown) | None => { + "https://doc.rust-lang.org/nightly/std/".to_string() + } }; // This is a primitive so the url is done "by hand". let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 7235217e29040..51a011cf19773 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -542,14 +542,3 @@ crate fn has_doc_flag(attrs: ty::Attributes<'_>, flag: Symbol) -> bool { && attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag)) }) } - -/// Return a channel suitable for using in a `doc.rust-lang.org/{channel}` format string. -crate fn doc_rust_lang_org_channel() -> &'static str { - match env!("CFG_RELEASE_CHANNEL") { - "stable" => env!("CFG_RELEASE_NUM"), - "beta" => "beta", - "nightly" | "dev" => "nightly", - // custom build of rustdoc maybe? link to the stable docs just in case - _ => "", - } -} diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b0d163763b4bd..7b0c0b6699653 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -406,18 +406,15 @@ crate fn run_global_ctxt( let mut krate = tcx.sess.time("clean_crate", || clean::krate(&mut ctxt)); if krate.module.doc_value().map(|d| d.is_empty()).unwrap_or(true) { - let help = format!( - "The following guide may be of use:\n\ - https://doc.rust-lang.org/{}/rustdoc/how-to-write-documentation.html", - crate::doc_rust_lang_org_channel(), - ); + let help = "The following guide may be of use:\n\ + https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html"; tcx.struct_lint_node( crate::lint::MISSING_CRATE_LEVEL_DOCS, DocContext::as_local_hir_id(tcx, krate.module.def_id).unwrap(), |lint| { let mut diag = lint.build("no documentation found for this crate's top-level module"); - diag.help(&help); + diag.help(help); diag.emit(); }, ); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 2a25b595625c9..169ef015fa88c 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -82,8 +82,6 @@ use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGro use rustc_session::getopts; use rustc_session::{early_error, early_warn}; -use crate::clean::utils::doc_rust_lang_org_channel; - /// A macro to create a FxHashMap. /// /// Example: @@ -606,10 +604,7 @@ fn usage(argv0: &str) { } println!("{}", options.usage(&format!("{} [options] ", argv0))); println!(" @path Read newline separated options from `path`\n"); - println!( - "More information available at https://doc.rust-lang.org/{}/rustdoc/what-is-rustdoc.html", - doc_rust_lang_org_channel() - ); + println!("More information available at https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html") } /// A result type used by several functions under `main()`. diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index c5fb54e52c7c4..25b6c187f3b27 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -2017,14 +2017,7 @@ fn disambiguator_error( msg: &str, ) { diag_info.link_range = disambiguator_range; - report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| { - let msg = format!( - "see https://doc.rust-lang.org/{}/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators \ - for more info about disambiguators", - crate::doc_rust_lang_org_channel(), - ); - diag.note(&msg); - }); + report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |_diag, _sp| {}); } /// Report an ambiguity error, where there were multiple possible resolutions. diff --git a/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr index f287f87408c48..de215b2163bd4 100644 --- a/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr +++ b/src/test/rustdoc-ui/intra-doc/email-address-localhost.stderr @@ -10,7 +10,6 @@ note: the lint level is defined here LL | #![deny(warnings)] | ^^^^^^^^ = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]` - = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr index 94d6d4616518e..195aaca32a27d 100644 --- a/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr +++ b/src/test/rustdoc-ui/intra-doc/unknown-disambiguator.stderr @@ -10,47 +10,36 @@ note: the lint level is defined here LL | #![deny(warnings)] | ^^^^^^^^ = note: `#[deny(rustdoc::broken_intra_doc_links)]` implied by `#[deny(warnings)]` - = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: unknown disambiguator `bar` --> $DIR/unknown-disambiguator.rs:3:35 | LL | //! Linking to [foo@banana] and [`bar@banana!()`]. | ^^^ - | - = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: unknown disambiguator `foo` --> $DIR/unknown-disambiguator.rs:9:34 | LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. | ^^^ - | - = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: unknown disambiguator `foo` --> $DIR/unknown-disambiguator.rs:9:48 | LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello]. | ^^^ - | - = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: unknown disambiguator `` --> $DIR/unknown-disambiguator.rs:6:31 | LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()). | ^ - | - = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: unknown disambiguator `` --> $DIR/unknown-disambiguator.rs:6:57 | LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()). | ^ - | - = note: see https://doc.rust-lang.org/nightly/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators error: aborting due to 6 previous errors From b6f3dbb65d0be4ecf94bb87f859db1f66b79f74d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 5 May 2021 16:40:06 +0200 Subject: [PATCH 7/9] Bump map_into_keys_values stable version to 1.54.0. --- library/alloc/src/collections/btree/map.rs | 28 +++++++++++----------- library/std/src/collections/hash/map.rs | 24 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 02e2924623c9d..0a46387c34e9c 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -398,12 +398,12 @@ impl fmt::Debug for ValuesMut<'_, K, V> { /// See its documentation for more. /// /// [`into_keys`]: BTreeMap::into_keys -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] pub struct IntoKeys { inner: IntoIter, } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl fmt::Debug for IntoKeys { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(key, _)| key)).finish() @@ -416,12 +416,12 @@ impl fmt::Debug for IntoKeys { /// See its documentation for more. /// /// [`into_values`]: BTreeMap::into_values -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] pub struct IntoValues { inner: IntoIter, } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl fmt::Debug for IntoValues { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() @@ -1252,7 +1252,7 @@ impl BTreeMap { /// assert_eq!(keys, [1, 2]); /// ``` #[inline] - #[stable(feature = "map_into_keys_values", since = "1.53.0")] + #[stable(feature = "map_into_keys_values", since = "1.54.0")] pub fn into_keys(self) -> IntoKeys { IntoKeys { inner: self.into_iter() } } @@ -1274,7 +1274,7 @@ impl BTreeMap { /// assert_eq!(values, ["hello", "goodbye"]); /// ``` #[inline] - #[stable(feature = "map_into_keys_values", since = "1.53.0")] + #[stable(feature = "map_into_keys_values", since = "1.54.0")] pub fn into_values(self) -> IntoValues { IntoValues { inner: self.into_iter() } } @@ -1774,7 +1774,7 @@ impl<'a, K, V> Range<'a, K, V> { } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl Iterator for IntoKeys { type Item = K; @@ -1799,24 +1799,24 @@ impl Iterator for IntoKeys { } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl DoubleEndedIterator for IntoKeys { fn next_back(&mut self) -> Option { self.inner.next_back().map(|(k, _)| k) } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl ExactSizeIterator for IntoKeys { fn len(&self) -> usize { self.inner.len() } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl FusedIterator for IntoKeys {} -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl Iterator for IntoValues { type Item = V; @@ -1833,21 +1833,21 @@ impl Iterator for IntoValues { } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl DoubleEndedIterator for IntoValues { fn next_back(&mut self) -> Option { self.inner.next_back().map(|(_, v)| v) } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl ExactSizeIterator for IntoValues { fn len(&self) -> usize { self.inner.len() } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl FusedIterator for IntoValues {} #[stable(feature = "btree_range", since = "1.17.0")] diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 32c868fb4ab04..84c7e2e9ea243 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -972,7 +972,7 @@ where /// let vec: Vec<&str> = map.into_keys().collect(); /// ``` #[inline] - #[stable(feature = "map_into_keys_values", since = "1.53.0")] + #[stable(feature = "map_into_keys_values", since = "1.54.0")] pub fn into_keys(self) -> IntoKeys { IntoKeys { inner: self.into_iter() } } @@ -994,7 +994,7 @@ where /// let vec: Vec = map.into_values().collect(); /// ``` #[inline] - #[stable(feature = "map_into_keys_values", since = "1.53.0")] + #[stable(feature = "map_into_keys_values", since = "1.54.0")] pub fn into_values(self) -> IntoValues { IntoValues { inner: self.into_iter() } } @@ -1409,7 +1409,7 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { /// map.insert("a", 1); /// let iter_keys = map.into_keys(); /// ``` -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] pub struct IntoKeys { inner: IntoIter, } @@ -1430,7 +1430,7 @@ pub struct IntoKeys { /// map.insert("a", 1); /// let iter_keys = map.into_values(); /// ``` -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] pub struct IntoValues { inner: IntoIter, } @@ -2131,7 +2131,7 @@ impl fmt::Debug for ValuesMut<'_, K, V> { } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl Iterator for IntoKeys { type Item = K; @@ -2144,24 +2144,24 @@ impl Iterator for IntoKeys { self.inner.size_hint() } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl ExactSizeIterator for IntoKeys { #[inline] fn len(&self) -> usize { self.inner.len() } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl FusedIterator for IntoKeys {} -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl fmt::Debug for IntoKeys { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish() } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl Iterator for IntoValues { type Item = V; @@ -2174,17 +2174,17 @@ impl Iterator for IntoValues { self.inner.size_hint() } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl ExactSizeIterator for IntoValues { #[inline] fn len(&self) -> usize { self.inner.len() } } -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl FusedIterator for IntoValues {} -#[stable(feature = "map_into_keys_values", since = "1.53.0")] +#[stable(feature = "map_into_keys_values", since = "1.54.0")] impl fmt::Debug for IntoValues { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish() From db555e1284dd37f4f3c76474aabfca09140a7ab3 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Wed, 24 Mar 2021 21:45:09 -0700 Subject: [PATCH 8/9] 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. --- compiler/rustc_ast_passes/src/feature_gate.rs | 39 ++++ .../rustc_codegen_cranelift/src/archive.rs | 4 +- .../rustc_codegen_llvm/src/back/archive.rs | 5 +- .../rustc_codegen_ssa/src/back/archive.rs | 16 +- compiler/rustc_codegen_ssa/src/back/link.rs | 73 +++++--- compiler/rustc_codegen_ssa/src/back/linker.rs | 124 +++++++++---- compiler/rustc_codegen_ssa/src/lib.rs | 3 +- compiler/rustc_feature/src/active.rs | 20 ++ compiler/rustc_interface/src/tests.rs | 173 +++++++++++++++--- compiler/rustc_metadata/src/native_libs.rs | 122 +++++++++--- .../src/rmeta/decoder/cstore_impl.rs | 11 +- compiler/rustc_middle/src/middle/cstore.rs | 1 + compiler/rustc_session/src/config.rs | 153 ++++++++++++---- compiler/rustc_session/src/options.rs | 4 +- compiler/rustc_session/src/utils.rs | 33 +++- compiler/rustc_span/src/symbol.rs | 6 + .../native-link-modifiers-as-needed.md | 18 ++ .../native-link-modifiers-bundle.md | 19 ++ .../native-link-modifiers-verbatim.md | 20 ++ .../native-link-modifiers-whole-archive.md | 18 ++ .../native-link-modifiers.md | 11 ++ .../feature-gate-native_link_modifiers.rs | 5 + .../feature-gate-native_link_modifiers.stderr | 12 ++ ...re-gate-native_link_modifiers_as_needed.rs | 8 + ...ate-native_link_modifiers_as_needed.stderr | 12 ++ ...ature-gate-native_link_modifiers_bundle.rs | 8 + ...e-gate-native_link_modifiers_bundle.stderr | 12 ++ ...ure-gate-native_link_modifiers_verbatim.rs | 8 + ...gate-native_link_modifiers_verbatim.stderr | 12 ++ ...ate-native_link_modifiers_whole_archive.rs | 8 + ...native_link_modifiers_whole_archive.stderr | 12 ++ .../feature-gate-static-nobundle-2.stderr | 2 + .../feature-gate-static-nobundle.rs | 3 +- .../feature-gate-static-nobundle.stderr | 8 +- .../native-library-link-flags/empty-kind-1.rs | 6 + .../empty-kind-1.stderr | 2 + .../native-library-link-flags/empty-kind-2.rs | 6 + .../empty-kind-2.stderr | 2 + 38 files changed, 829 insertions(+), 170 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/native-link-modifiers-as-needed.md create mode 100644 src/doc/unstable-book/src/language-features/native-link-modifiers-bundle.md create mode 100644 src/doc/unstable-book/src/language-features/native-link-modifiers-verbatim.md create mode 100644 src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md create mode 100644 src/doc/unstable-book/src/language-features/native-link-modifiers.md create mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs create mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs create mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs create mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs create mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr create mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs create mode 100644 src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr create mode 100644 src/test/ui/native-library-link-flags/empty-kind-1.rs create mode 100644 src/test/ui/native-library-link-flags/empty-kind-1.stderr create mode 100644 src/test/ui/native-library-link-flags/empty-kind-2.rs create mode 100644 src/test/ui/native-library-link-flags/empty-kind-2.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index da516f5cb4129..dc3383dae843e 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -326,6 +326,45 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } } + + // Check for unstable modifiers on `#[link(..)]` attribute + if self.sess.check_name(attr, sym::link) { + for nested_meta in attr.meta_item_list().unwrap_or_default() { + if nested_meta.has_name(sym::modifiers) { + gate_feature_post!( + self, + native_link_modifiers, + nested_meta.span(), + "native link modifiers are experimental" + ); + + if let Some(modifiers) = nested_meta.value_str() { + for modifier in modifiers.as_str().split(',') { + if let Some(modifier) = modifier.strip_prefix(&['+', '-'][..]) { + macro_rules! gate_modifier { ($($name:literal => $feature:ident)*) => { + $(if modifier == $name { + let msg = concat!("`#[link(modifiers=\"", $name, "\")]` is unstable"); + gate_feature_post!( + self, + $feature, + nested_meta.name_value_literal_span().unwrap(), + msg + ); + })* + }} + + gate_modifier!( + "bundle" => native_link_modifiers_bundle + "verbatim" => native_link_modifiers_verbatim + "whole-archive" => native_link_modifiers_whole_archive + "as-needed" => native_link_modifiers_as_needed + ); + } + } + } + } + } + } } fn visit_item(&mut self, i: &'a ast::Item) { diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index 7583fc424071e..fc0823302e018 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -85,8 +85,8 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { )); } - fn add_native_library(&mut self, name: rustc_span::symbol::Symbol) { - let location = find_library(name, &self.lib_search_paths, self.sess); + fn add_native_library(&mut self, name: rustc_span::symbol::Symbol, verbatim: bool) { + let location = find_library(name, verbatim, &self.lib_search_paths, self.sess); self.add_archive(location.clone(), |_| false).unwrap_or_else(|e| { panic!("failed to add native library {}: {}", location.to_string_lossy(), e); }); diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 4e7213853b015..261affe2c427e 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -100,8 +100,9 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { /// Adds all of the contents of a native library to this archive. This will /// search in the relevant locations for a library named `name`. - fn add_native_library(&mut self, name: Symbol) { - let location = find_library(name, &self.config.lib_search_paths, self.config.sess); + fn add_native_library(&mut self, name: Symbol, verbatim: bool) { + let location = + find_library(name, verbatim, &self.config.lib_search_paths, self.config.sess); self.add_archive(&location, |_| false).unwrap_or_else(|e| { self.config.sess.fatal(&format!( "failed to add native library {}: {}", diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index c477ac6462acb..c197d48d4ea64 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -4,11 +4,19 @@ use rustc_span::symbol::Symbol; use std::io; use std::path::{Path, PathBuf}; -pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> PathBuf { +pub fn find_library( + name: Symbol, + verbatim: bool, + search_paths: &[PathBuf], + sess: &Session, +) -> PathBuf { // On Windows, static libraries sometimes show up as libfoo.a and other // times show up as foo.lib - let oslibname = - format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix); + let oslibname = if verbatim { + name.to_string() + } else { + format!("{}{}{}", sess.target.staticlib_prefix, name, sess.target.staticlib_suffix) + }; let unixlibname = format!("lib{}.a", name); for path in search_paths { @@ -45,7 +53,7 @@ pub trait ArchiveBuilder<'a> { lto: bool, skip_objects: bool, ) -> io::Result<()>; - fn add_native_library(&mut self, name: Symbol); + fn add_native_library(&mut self, name: Symbol, verbatim: bool); fn update_symbols(&mut self); fn build(self); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index dcdd0910aa6af..59f66c55572af 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -329,15 +329,15 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( // metadata of the rlib we're generating somehow. for lib in codegen_results.crate_info.used_libraries.iter() { match lib.kind { - NativeLibKind::StaticBundle => {} - NativeLibKind::StaticNoBundle - | NativeLibKind::Dylib - | NativeLibKind::Framework + NativeLibKind::Static { bundle: None | Some(true), .. } => {} + NativeLibKind::Static { bundle: Some(false), .. } + | NativeLibKind::Dylib { .. } + | NativeLibKind::Framework { .. } | NativeLibKind::RawDylib | NativeLibKind::Unspecified => continue, } if let Some(name) = lib.name { - ab.add_native_library(name); + ab.add_native_library(name, lib.verbatim.unwrap_or(false)); } } @@ -430,9 +430,10 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>( // Clearly this is not sufficient for a general purpose feature, and // we'd want to read from the library's metadata to determine which // object files come from where and selectively skip them. - let skip_object_files = native_libs - .iter() - .any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib)); + let skip_object_files = native_libs.iter().any(|lib| { + matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. }) + && !relevant_lib(sess, lib) + }); ab.add_rlib( path, &name.as_str(), @@ -931,7 +932,7 @@ fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) { let path = find_sanitizer_runtime(&sess, &filename); let rpath = path.to_str().expect("non-utf8 component in path"); linker.args(&["-Wl,-rpath", "-Xlinker", rpath]); - linker.link_dylib(Symbol::intern(&filename)); + linker.link_dylib(Symbol::intern(&filename), false, true); } else { let filename = format!("librustc{}_rt.{}.a", channel, name); let path = find_sanitizer_runtime(&sess, &filename).join(&filename); @@ -1080,21 +1081,25 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { .filter_map(|lib| { let name = lib.name?; match lib.kind { - NativeLibKind::StaticNoBundle - | NativeLibKind::Dylib + NativeLibKind::Static { bundle: Some(false), .. } + | NativeLibKind::Dylib { .. } | NativeLibKind::Unspecified => { + let verbatim = lib.verbatim.unwrap_or(false); if sess.target.is_like_msvc { - Some(format!("{}.lib", name)) + Some(format!("{}{}", name, if verbatim { "" } else { ".lib" })) + } else if sess.target.linker_is_gnu { + Some(format!("-l{}{}", if verbatim { ":" } else { "" }, name)) } else { Some(format!("-l{}", name)) } } - NativeLibKind::Framework => { + NativeLibKind::Framework { .. } => { // ld-only syntax, since there are no frameworks in MSVC Some(format!("-framework {}", name)) } // These are included, no need to print them - NativeLibKind::StaticBundle | NativeLibKind::RawDylib => None, + NativeLibKind::Static { bundle: None | Some(true), .. } + | NativeLibKind::RawDylib => None, } }) .collect(); @@ -1812,11 +1817,20 @@ fn add_local_native_libraries( Some(l) => l, None => continue, }; + let verbatim = lib.verbatim.unwrap_or(false); match lib.kind { - NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name), - NativeLibKind::Framework => cmd.link_framework(name), - NativeLibKind::StaticNoBundle => cmd.link_staticlib(name), - NativeLibKind::StaticBundle => cmd.link_whole_staticlib(name, &search_path), + NativeLibKind::Dylib { as_needed } => { + cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true)) + } + NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true), + NativeLibKind::Framework { as_needed } => { + cmd.link_framework(name, as_needed.unwrap_or(true)) + } + NativeLibKind::Static { bundle: None | Some(true), .. } + | NativeLibKind::Static { whole_archive: Some(true), .. } => { + cmd.link_whole_staticlib(name, verbatim, &search_path); + } + NativeLibKind::Static { .. } => cmd.link_staticlib(name, verbatim), NativeLibKind::RawDylib => { // FIXME(#58713): Proper handling for raw dylibs. bug!("raw_dylib feature not yet implemented"); @@ -2000,9 +2014,10 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( // there's a static library that's not relevant we skip all object // files. let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; - let skip_native = native_libs - .iter() - .any(|lib| lib.kind == NativeLibKind::StaticBundle && !relevant_lib(sess, lib)); + let skip_native = native_libs.iter().any(|lib| { + matches!(lib.kind, NativeLibKind::Static { bundle: None | Some(true), .. }) + && !relevant_lib(sess, lib) + }); if (!are_upstream_rust_objects_already_included(sess) || ignored_for_lto(sess, &codegen_results.crate_info, cnum)) @@ -2144,22 +2159,28 @@ fn add_upstream_native_libraries( if !relevant_lib(sess, &lib) { continue; } + let verbatim = lib.verbatim.unwrap_or(false); match lib.kind { - NativeLibKind::Dylib | NativeLibKind::Unspecified => cmd.link_dylib(name), - NativeLibKind::Framework => cmd.link_framework(name), - NativeLibKind::StaticNoBundle => { + NativeLibKind::Dylib { as_needed } => { + cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true)) + } + NativeLibKind::Unspecified => cmd.link_dylib(name, verbatim, true), + NativeLibKind::Framework { as_needed } => { + cmd.link_framework(name, as_needed.unwrap_or(true)) + } + NativeLibKind::Static { bundle: Some(false), .. } => { // Link "static-nobundle" native libs only if the crate they originate from // is being linked statically to the current crate. If it's linked dynamically // or is an rlib already included via some other dylib crate, the symbols from // native libs will have already been included in that dylib. if data[cnum.as_usize() - 1] == Linkage::Static { - cmd.link_staticlib(name) + cmd.link_staticlib(name, verbatim) } } // ignore statically included native libraries here as we've // already included them when we included the rust library // previously - NativeLibKind::StaticBundle => {} + NativeLibKind::Static { bundle: None | Some(true), .. } => {} NativeLibKind::RawDylib => { // FIXME(#58713): Proper handling for raw dylibs. bug!("raw_dylib feature not yet implemented"); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 77d8ab49ff258..e7758ee52f473 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -103,18 +103,19 @@ impl LinkerInfo { pub trait Linker { fn cmd(&mut self) -> &mut Command; fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); - fn link_dylib(&mut self, lib: Symbol); + fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool); fn link_rust_dylib(&mut self, lib: Symbol, path: &Path); - fn link_framework(&mut self, framework: Symbol); - fn link_staticlib(&mut self, lib: Symbol); + fn link_framework(&mut self, framework: Symbol, as_needed: bool); + fn link_staticlib(&mut self, lib: Symbol, verbatim: bool); fn link_rlib(&mut self, lib: &Path); fn link_whole_rlib(&mut self, lib: &Path); - fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]); + fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]); fn include_path(&mut self, path: &Path); fn framework_path(&mut self, path: &Path); fn output_filename(&mut self, path: &Path); fn add_object(&mut self, path: &Path); fn gc_sections(&mut self, keep_metadata: bool); + fn no_gc_sections(&mut self); fn full_relro(&mut self); fn partial_relro(&mut self); fn no_relro(&mut self); @@ -338,13 +339,32 @@ impl<'a> Linker for GccLinker<'a> { } } - fn link_dylib(&mut self, lib: Symbol) { + fn link_dylib(&mut self, lib: Symbol, verbatim: bool, as_needed: bool) { + if !as_needed { + if self.sess.target.is_like_osx { + // FIXME(81490): ld64 doesn't support these flags but macOS 11 + // has -needed-l{} / -needed_library {} + // but we have no way to detect that here. + self.sess.warn("`as-needed` modifier not implemented yet for ld64"); + } else if self.sess.target.linker_is_gnu { + self.linker_arg("--no-as-needed"); + } else { + self.sess.warn("`as-needed` modifier not supported for current linker"); + } + } self.hint_dynamic(); - self.cmd.arg(format!("-l{}", lib)); + self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib)); + if !as_needed { + if self.sess.target.is_like_osx { + // See above FIXME comment + } else if self.sess.target.linker_is_gnu { + self.linker_arg("--as-needed"); + } + } } - fn link_staticlib(&mut self, lib: Symbol) { + fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) { self.hint_static(); - self.cmd.arg(format!("-l{}", lib)); + self.cmd.arg(format!("-l{}{}", if verbatim { ":" } else { "" }, lib)); } fn link_rlib(&mut self, lib: &Path) { self.hint_static(); @@ -378,8 +398,14 @@ impl<'a> Linker for GccLinker<'a> { self.cmd.arg(format!("-l{}", lib)); } - fn link_framework(&mut self, framework: Symbol) { + fn link_framework(&mut self, framework: Symbol, as_needed: bool) { self.hint_dynamic(); + if !as_needed { + // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework + // flag but we have no way to detect that here. + // self.cmd.arg("-needed_framework").sym_arg(framework); + self.sess.warn("`as-needed` modifier not implemented yet for ld64"); + } self.cmd.arg("-framework").sym_arg(framework); } @@ -389,17 +415,21 @@ impl<'a> Linker for GccLinker<'a> { // don't otherwise explicitly reference them. This can occur for // libraries which are just providing bindings, libraries with generic // functions, etc. - fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, search_path: &[PathBuf]) { self.hint_static(); let target = &self.sess.target; if !target.is_like_osx { - self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib)); + self.linker_arg("--whole-archive").cmd.arg(format!( + "-l{}{}", + if verbatim { ":" } else { "" }, + lib + )); self.linker_arg("--no-whole-archive"); } else { // -force_load is the macOS equivalent of --whole-archive, but it // involves passing the full path to the library to link. self.linker_arg("-force_load"); - let lib = archive::find_library(lib, search_path, &self.sess); + let lib = archive::find_library(lib, verbatim, search_path, &self.sess); self.linker_arg(&lib); } } @@ -445,6 +475,16 @@ impl<'a> Linker for GccLinker<'a> { } } + fn no_gc_sections(&mut self) { + if self.sess.target.is_like_osx { + self.linker_arg("-no_dead_strip"); + } else if self.sess.target.is_like_solaris { + self.linker_arg("-zrecord"); + } else { + self.linker_arg("--no-gc-sections"); + } + } + fn optimize(&mut self) { if !self.sess.target.linker_is_gnu { return; @@ -708,8 +748,12 @@ impl<'a> Linker for MsvcLinker<'a> { } } - fn link_dylib(&mut self, lib: Symbol) { - self.cmd.arg(&format!("{}.lib", lib)); + fn no_gc_sections(&mut self) { + self.cmd.arg("/OPT:NOREF,NOICF"); + } + + fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) { + self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); } fn link_rust_dylib(&mut self, lib: Symbol, path: &Path) { @@ -723,8 +767,8 @@ impl<'a> Linker for MsvcLinker<'a> { } } - fn link_staticlib(&mut self, lib: Symbol) { - self.cmd.arg(&format!("{}.lib", lib)); + fn link_staticlib(&mut self, lib: Symbol, verbatim: bool) { + self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); } fn full_relro(&mut self) { @@ -762,13 +806,13 @@ impl<'a> Linker for MsvcLinker<'a> { fn framework_path(&mut self, _path: &Path) { bug!("frameworks are not supported on windows") } - fn link_framework(&mut self, _framework: Symbol) { + fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { bug!("frameworks are not supported on windows") } - fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) { - self.link_staticlib(lib); - self.cmd.arg(format!("/WHOLEARCHIVE:{}.lib", lib)); + fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) { + self.link_staticlib(lib, verbatim); + self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" })); } fn link_whole_rlib(&mut self, path: &Path) { self.link_rlib(path); @@ -917,7 +961,7 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.arg("-L").arg(path); } - fn link_staticlib(&mut self, lib: Symbol) { + fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) { self.cmd.arg("-l").sym_arg(lib); } @@ -929,14 +973,14 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.arg(path); } - fn link_dylib(&mut self, lib: Symbol) { + fn link_dylib(&mut self, lib: Symbol, verbatim: bool, _as_needed: bool) { // Emscripten always links statically - self.link_staticlib(lib); + self.link_staticlib(lib, verbatim); } - fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, lib: Symbol, verbatim: bool, _search_path: &[PathBuf]) { // not supported? - self.link_staticlib(lib); + self.link_staticlib(lib, verbatim); } fn link_whole_rlib(&mut self, lib: &Path) { @@ -945,7 +989,7 @@ impl<'a> Linker for EmLinker<'a> { } fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) { - self.link_dylib(lib); + self.link_dylib(lib, false, true); } fn link_rlib(&mut self, lib: &Path) { @@ -968,7 +1012,7 @@ impl<'a> Linker for EmLinker<'a> { bug!("frameworks are not supported on Emscripten") } - fn link_framework(&mut self, _framework: Symbol) { + fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { bug!("frameworks are not supported on Emscripten") } @@ -976,6 +1020,10 @@ impl<'a> Linker for EmLinker<'a> { // noop } + fn no_gc_sections(&mut self) { + // noop + } + fn optimize(&mut self) { // Emscripten performs own optimizations self.cmd.arg(match self.sess.opts.optimize { @@ -1119,11 +1167,11 @@ impl<'a> Linker for WasmLd<'a> { } } - fn link_dylib(&mut self, lib: Symbol) { + fn link_dylib(&mut self, lib: Symbol, _verbatim: bool, _as_needed: bool) { self.cmd.arg("-l").sym_arg(lib); } - fn link_staticlib(&mut self, lib: Symbol) { + fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) { self.cmd.arg("-l").sym_arg(lib); } @@ -1157,11 +1205,11 @@ impl<'a> Linker for WasmLd<'a> { self.cmd.arg("-l").sym_arg(lib); } - fn link_framework(&mut self, _framework: Symbol) { + fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { panic!("frameworks not supported") } - fn link_whole_staticlib(&mut self, lib: Symbol, _search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { self.cmd.arg("-l").sym_arg(lib); } @@ -1173,6 +1221,10 @@ impl<'a> Linker for WasmLd<'a> { self.cmd.arg("--gc-sections"); } + fn no_gc_sections(&mut self) { + self.cmd.arg("--no-gc-sections"); + } + fn optimize(&mut self) { self.cmd.arg(match self.sess.opts.optimize { OptLevel::No => "-O0", @@ -1327,7 +1379,7 @@ impl<'a> Linker for PtxLinker<'a> { }); } - fn link_dylib(&mut self, _lib: Symbol) { + fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) { panic!("external dylibs not supported") } @@ -1335,11 +1387,11 @@ impl<'a> Linker for PtxLinker<'a> { panic!("external dylibs not supported") } - fn link_staticlib(&mut self, _lib: Symbol) { + fn link_staticlib(&mut self, _lib: Symbol, _verbatim: bool) { panic!("staticlibs not supported") } - fn link_whole_staticlib(&mut self, _lib: Symbol, _search_path: &[PathBuf]) { + fn link_whole_staticlib(&mut self, _lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) { panic!("staticlibs not supported") } @@ -1347,7 +1399,7 @@ impl<'a> Linker for PtxLinker<'a> { panic!("frameworks not supported") } - fn link_framework(&mut self, _framework: Symbol) { + fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) { panic!("frameworks not supported") } @@ -1359,6 +1411,8 @@ impl<'a> Linker for PtxLinker<'a> { fn gc_sections(&mut self, _keep_metadata: bool) {} + fn no_gc_sections(&mut self) {} + fn pgo_gen(&mut self) {} fn no_crt_objects(&mut self) {} diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index f0f45b067b352..1b53b55190164 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -114,11 +114,12 @@ pub struct NativeLib { pub kind: NativeLibKind, pub name: Option, pub cfg: Option, + pub verbatim: Option, } impl From<&cstore::NativeLib> for NativeLib { fn from(lib: &cstore::NativeLib) -> Self { - NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone() } + NativeLib { kind: lib.kind, name: lib.name, cfg: lib.cfg.clone(), verbatim: lib.verbatim } } } diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 4ad5f085ad055..f747f8545145e 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -656,6 +656,21 @@ declare_features! ( /// Allows using imported `main` function (active, imported_main, "1.53.0", Some(28937), None), + /// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]` + (active, native_link_modifiers, "1.53.0", Some(81490), None), + + /// Allows specifying the bundle link modifier + (active, native_link_modifiers_bundle, "1.53.0", Some(81490), None), + + /// Allows specifying the verbatim link modifier + (active, native_link_modifiers_verbatim, "1.53.0", Some(81490), None), + + /// Allows specifying the whole-archive link modifier + (active, native_link_modifiers_whole_archive, "1.53.0", Some(81490), None), + + /// Allows specifying the as-needed link modifier + (active, native_link_modifiers_as_needed, "1.53.0", Some(81490), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -683,6 +698,11 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::const_generics_defaults, sym::inherent_associated_types, sym::type_alias_impl_trait, + sym::native_link_modifiers, + sym::native_link_modifiers_bundle, + sym::native_link_modifiers_verbatim, + sym::native_link_modifiers_whole_archive, + sym::native_link_modifiers_as_needed, ]; /// Some features are not allowed to be used together at the same time, if diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index d8c1a7a268220..4d87bbead41cb 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -12,7 +12,7 @@ use rustc_session::config::{ }; use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; -use rustc_session::utils::{CanonicalizedPath, NativeLibKind}; +use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use rustc_session::{build_session, getopts, DiagnosticOutput, Session}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; @@ -303,38 +303,122 @@ fn test_native_libs_tracking_hash_different_values() { let mut v2 = Options::default(); let mut v3 = Options::default(); let mut v4 = Options::default(); + let mut v5 = Options::default(); // Reference v1.libs = vec![ - (String::from("a"), None, NativeLibKind::StaticBundle), - (String::from("b"), None, NativeLibKind::Framework), - (String::from("c"), None, NativeLibKind::Unspecified), + NativeLib { + name: String::from("a"), + new_name: None, + kind: NativeLibKind::Static { bundle: None, whole_archive: None }, + verbatim: None, + }, + NativeLib { + name: String::from("b"), + new_name: None, + kind: NativeLibKind::Framework { as_needed: None }, + verbatim: None, + }, + NativeLib { + name: String::from("c"), + new_name: None, + kind: NativeLibKind::Unspecified, + verbatim: None, + }, ]; // Change label v2.libs = vec![ - (String::from("a"), None, NativeLibKind::StaticBundle), - (String::from("X"), None, NativeLibKind::Framework), - (String::from("c"), None, NativeLibKind::Unspecified), + NativeLib { + name: String::from("a"), + new_name: None, + kind: NativeLibKind::Static { bundle: None, whole_archive: None }, + verbatim: None, + }, + NativeLib { + name: String::from("X"), + new_name: None, + kind: NativeLibKind::Framework { as_needed: None }, + verbatim: None, + }, + NativeLib { + name: String::from("c"), + new_name: None, + kind: NativeLibKind::Unspecified, + verbatim: None, + }, ]; // Change kind v3.libs = vec![ - (String::from("a"), None, NativeLibKind::StaticBundle), - (String::from("b"), None, NativeLibKind::StaticBundle), - (String::from("c"), None, NativeLibKind::Unspecified), + NativeLib { + name: String::from("a"), + new_name: None, + kind: NativeLibKind::Static { bundle: None, whole_archive: None }, + verbatim: None, + }, + NativeLib { + name: String::from("b"), + new_name: None, + kind: NativeLibKind::Static { bundle: None, whole_archive: None }, + verbatim: None, + }, + NativeLib { + name: String::from("c"), + new_name: None, + kind: NativeLibKind::Unspecified, + verbatim: None, + }, ]; // Change new-name v4.libs = vec![ - (String::from("a"), None, NativeLibKind::StaticBundle), - (String::from("b"), Some(String::from("X")), NativeLibKind::Framework), - (String::from("c"), None, NativeLibKind::Unspecified), + NativeLib { + name: String::from("a"), + new_name: None, + kind: NativeLibKind::Static { bundle: None, whole_archive: None }, + verbatim: None, + }, + NativeLib { + name: String::from("b"), + new_name: Some(String::from("X")), + kind: NativeLibKind::Framework { as_needed: None }, + verbatim: None, + }, + NativeLib { + name: String::from("c"), + new_name: None, + kind: NativeLibKind::Unspecified, + verbatim: None, + }, + ]; + + // Change verbatim + v5.libs = vec![ + NativeLib { + name: String::from("a"), + new_name: None, + kind: NativeLibKind::Static { bundle: None, whole_archive: None }, + verbatim: None, + }, + NativeLib { + name: String::from("b"), + new_name: None, + kind: NativeLibKind::Framework { as_needed: None }, + verbatim: Some(true), + }, + NativeLib { + name: String::from("c"), + new_name: None, + kind: NativeLibKind::Unspecified, + verbatim: None, + }, ]; assert_different_hash(&v1, &v2); assert_different_hash(&v1, &v3); assert_different_hash(&v1, &v4); + assert_different_hash(&v1, &v5); } #[test] @@ -345,21 +429,66 @@ fn test_native_libs_tracking_hash_different_order() { // Reference v1.libs = vec![ - (String::from("a"), None, NativeLibKind::StaticBundle), - (String::from("b"), None, NativeLibKind::Framework), - (String::from("c"), None, NativeLibKind::Unspecified), + NativeLib { + name: String::from("a"), + new_name: None, + kind: NativeLibKind::Static { bundle: None, whole_archive: None }, + verbatim: None, + }, + NativeLib { + name: String::from("b"), + new_name: None, + kind: NativeLibKind::Framework { as_needed: None }, + verbatim: None, + }, + NativeLib { + name: String::from("c"), + new_name: None, + kind: NativeLibKind::Unspecified, + verbatim: None, + }, ]; v2.libs = vec![ - (String::from("b"), None, NativeLibKind::Framework), - (String::from("a"), None, NativeLibKind::StaticBundle), - (String::from("c"), None, NativeLibKind::Unspecified), + NativeLib { + name: String::from("b"), + new_name: None, + kind: NativeLibKind::Framework { as_needed: None }, + verbatim: None, + }, + NativeLib { + name: String::from("a"), + new_name: None, + kind: NativeLibKind::Static { bundle: None, whole_archive: None }, + verbatim: None, + }, + NativeLib { + name: String::from("c"), + new_name: None, + kind: NativeLibKind::Unspecified, + verbatim: None, + }, ]; v3.libs = vec![ - (String::from("c"), None, NativeLibKind::Unspecified), - (String::from("a"), None, NativeLibKind::StaticBundle), - (String::from("b"), None, NativeLibKind::Framework), + NativeLib { + name: String::from("c"), + new_name: None, + kind: NativeLibKind::Unspecified, + verbatim: None, + }, + NativeLib { + name: String::from("a"), + new_name: None, + kind: NativeLibKind::Static { bundle: None, whole_archive: None }, + verbatim: None, + }, + NativeLib { + name: String::from("b"), + new_name: None, + kind: NativeLibKind::Framework { as_needed: None }, + verbatim: None, + }, ]; assert_same_hash(&v1, &v2); diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 523e016eeb9f2..bc342119efb99 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 { @@ -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::>(); if existing.is_empty() { // Add if not found - let new_name = new_name.as_ref().map(|s| &**s); // &Option -> Option<&str> + let new_name = passed_lib.new_name.as_ref().map(|s| &**s); // &Option -> 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 8595a70dd9478..b11ad6c7ff867 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) diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index 4f1ca968c3018..82b9ebcc7eca3 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -94,6 +94,7 @@ pub struct NativeLib { pub cfg: Option, pub foreign_module: Option, pub wasm_import_module: Option, + pub verbatim: Option, } #[derive(Clone, TyEncodable, TyDecodable, HashStable, Debug)] diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 08d6f4a46fefe..6956b815f1922 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -5,7 +5,7 @@ pub use crate::options::*; use crate::lint; use crate::search_paths::SearchPath; -use crate::utils::{CanonicalizedPath, NativeLibKind}; +use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use crate::{early_error, early_warn, Session}; use rustc_data_structures::fx::FxHashSet; @@ -1027,8 +1027,11 @@ pub fn rustc_short_optgroups() -> Vec { "", "Link the generated crate(s) to the specified native library NAME. The optional KIND can be one of - static, framework, or dylib (the default).", - "[KIND=]NAME", + static, framework, or dylib (the default). + Optional comma separated MODIFIERS (bundle|verbatim|whole-archive|as-needed) + may be specified each with a prefix of either '+' to + enable or '-' to disable.", + "[KIND[:MODIFIERS]=]NAME[:RENAME]", ), make_crate_type_option(), opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"), @@ -1591,52 +1594,127 @@ fn select_debuginfo( } } -fn parse_libs( - matches: &getopts::Matches, +fn parse_native_lib_kind(kind: &str, error_format: ErrorOutputType) -> NativeLibKind { + match kind { + "dylib" => NativeLibKind::Dylib { as_needed: None }, + "framework" => NativeLibKind::Framework { as_needed: None }, + "static" => NativeLibKind::Static { bundle: None, whole_archive: None }, + "static-nobundle" => { + early_warn( + error_format, + "library kind `static-nobundle` has been superseded by specifying \ + `-bundle` on library kind `static`. Try `static:-bundle`", + ); + NativeLibKind::Static { bundle: Some(false), whole_archive: None } + } + s => early_error( + error_format, + &format!("unknown library kind `{}`, expected one of dylib, framework, or static", s), + ), + } +} + +fn parse_native_lib_modifiers( + is_nightly: bool, + mut kind: NativeLibKind, + modifiers: &str, error_format: ErrorOutputType, -) -> Vec<(String, Option, NativeLibKind)> { +) -> (NativeLibKind, Option) { + let mut verbatim = None; + for modifier in modifiers.split(',') { + let (modifier, value) = match modifier.strip_prefix(&['+', '-'][..]) { + Some(m) => (m, modifier.starts_with('+')), + None => early_error( + error_format, + "invalid linking modifier syntax, expected '+' or '-' prefix \ + before one of: bundle, verbatim, whole-archive, as-needed", + ), + }; + + if !is_nightly { + early_error( + error_format, + "linking modifiers are currently unstable and only accepted on \ + the nightly compiler", + ); + } + + match (modifier, &mut kind) { + ("bundle", NativeLibKind::Static { bundle, .. }) => { + *bundle = Some(value); + } + ("bundle", _) => early_error( + error_format, + "bundle linking modifier is only compatible with \ + `static` linking kind", + ), + + ("verbatim", _) => verbatim = Some(value), + + ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => { + *whole_archive = Some(value); + } + ("whole-archive", _) => early_error( + error_format, + "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", _) => early_error( + error_format, + "as-needed linking modifier is only compatible with \ + `dylib` and `framework` linking kinds", + ), + + _ => early_error( + error_format, + &format!( + "unrecognized linking modifier `{}`, expected one \ + of: bundle, verbatim, whole-archive, as-needed", + modifier + ), + ), + } + } + + (kind, verbatim) +} + +fn parse_libs(matches: &getopts::Matches, error_format: ErrorOutputType) -> Vec { + let is_nightly = nightly_options::match_is_nightly_build(matches); matches .opt_strs("l") .into_iter() .map(|s| { - // Parse string of the form "[KIND=]lib[:new_name]", - // where KIND is one of "dylib", "framework", "static". - let (name, kind) = match s.split_once('=') { - None => (s, NativeLibKind::Unspecified), + // Parse string of the form "[KIND[:MODIFIERS]=]lib[:new_name]", + // where KIND is one of "dylib", "framework", "static" and + // where MODIFIERS are a comma separated list of supported modifiers + // (bundle, verbatim, whole-archive, as-needed). Each modifier is prefixed + // with either + or - to indicate whether it is enabled or disabled. + // The last value specified for a given modifier wins. + let (name, kind, verbatim) = match s.split_once('=') { + None => (s, NativeLibKind::Unspecified, None), Some((kind, name)) => { - let kind = match kind { - "dylib" => NativeLibKind::Dylib, - "framework" => NativeLibKind::Framework, - "static" => NativeLibKind::StaticBundle, - "static-nobundle" => NativeLibKind::StaticNoBundle, - s => { - early_error( - error_format, - &format!( - "unknown library kind `{}`, expected \ - one of dylib, framework, or static", - s - ), - ); + let (kind, verbatim) = match kind.split_once(':') { + None => (parse_native_lib_kind(kind, error_format), None), + Some((kind, modifiers)) => { + let kind = parse_native_lib_kind(kind, error_format); + parse_native_lib_modifiers(is_nightly, kind, modifiers, error_format) } }; - (name.to_string(), kind) + (name.to_string(), kind, verbatim) } }; - if kind == NativeLibKind::StaticNoBundle - && !nightly_options::match_is_nightly_build(matches) - { - early_error( - error_format, - "the library kind 'static-nobundle' is only \ - accepted on the nightly compiler", - ); - } + let (name, new_name) = match name.split_once(':') { None => (name, None), Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())), }; - (name, new_name, kind) + NativeLib { name, new_name, kind, verbatim } }) .collect() } @@ -2316,7 +2394,7 @@ crate mod dep_tracking { }; use crate::lint; use crate::options::WasiExecModel; - use crate::utils::NativeLibKind; + use crate::utils::{NativeLib, NativeLibKind}; use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel}; @@ -2391,6 +2469,7 @@ crate mod dep_tracking { DebugInfo, UnstableFeatures, OutputTypes, + NativeLib, NativeLibKind, SanitizerSet, CFGuard, @@ -2409,8 +2488,8 @@ crate mod dep_tracking { PathBuf, (PathBuf, PathBuf), CrateType, + NativeLib, (String, lint::Level), - (String, Option, NativeLibKind), (String, u64) ); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index cd28517bfbc3a..7799dfd19782a 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -3,7 +3,7 @@ use crate::config::*; use crate::early_error; use crate::lint; use crate::search_paths::SearchPath; -use crate::utils::NativeLibKind; +use crate::utils::NativeLib; use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet}; use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel}; @@ -133,7 +133,7 @@ top_level_options!( describe_lints: bool [UNTRACKED], output_types: OutputTypes [TRACKED], search_paths: Vec [UNTRACKED], - libs: Vec<(String, Option, NativeLibKind)> [TRACKED], + libs: Vec [TRACKED], maybe_sysroot: Option [UNTRACKED], target_triple: TargetTriple [TRACKED], diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index e9d597d1ba65c..1a044e677a02f 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -19,25 +19,42 @@ impl Session { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] pub enum NativeLibKind { - /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included - /// when linking a final binary, but not when archiving an rlib. - StaticNoBundle, - /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) included - /// when linking a final binary, but also included when archiving an rlib. - StaticBundle, + /// Static library (e.g. `libfoo.a` on Linux or `foo.lib` on Windows/MSVC) + Static { + /// Whether to bundle objects from static library into produced rlib + bundle: Option, + /// Whether to link static library without throwing any object files away + whole_archive: Option, + }, /// Dynamic library (e.g. `libfoo.so` on Linux) /// or an import library corresponding to a dynamic library (e.g. `foo.lib` on Windows/MSVC). - Dylib, + Dylib { + /// Whether the dynamic library will be linked only if it satifies some undefined symbols + as_needed: Option, + }, /// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library. RawDylib, /// A macOS-specific kind of dynamic libraries. - Framework, + Framework { + /// Whether the framework will be linked only if it satifies some undefined symbols + as_needed: Option, + }, /// The library kind wasn't specified, `Dylib` is currently used as a default. Unspecified, } rustc_data_structures::impl_stable_hash_via_hash!(NativeLibKind); +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable)] +pub struct NativeLib { + pub name: String, + pub new_name: Option, + pub kind: NativeLibKind, + pub verbatim: Option, +} + +rustc_data_structures::impl_stable_hash_via_hash!(NativeLib); + /// A path that has been canonicalized along with its original, non-canonicalized form #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct CanonicalizedPath { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b2dac10c83fac..4c80b84e3d275 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -748,6 +748,7 @@ symbols! { minnumf64, mips_target_feature, misc, + modifiers, module, module_path, more_struct_aliases, @@ -763,6 +764,11 @@ symbols! { naked, naked_functions, name, + native_link_modifiers, + native_link_modifiers_as_needed, + native_link_modifiers_bundle, + native_link_modifiers_verbatim, + native_link_modifiers_whole_archive, ne, nearbyintf32, nearbyintf64, diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-as-needed.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-as-needed.md new file mode 100644 index 0000000000000..1757673612c48 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/native-link-modifiers-as-needed.md @@ -0,0 +1,18 @@ +# `native_link_modifiers_as_needed` + +The tracking issue for this feature is: [#81490] + +[#81490]: https://github.com/rust-lang/rust/issues/81490 + +------------------------ + +The `native_link_modifiers_as_needed` feature allows you to use the `as-needed` modifier. + +`as-needed` is only compatible with the `dynamic` and `framework` linking kinds. Using any other kind will result in a compiler error. + +`+as-needed` means that the library will be actually linked only if it satisfies some undefined symbols at the point at which it is specified on the command line, making it similar to static libraries in this regard. + +This modifier translates to `--as-needed` for ld-like linkers, and to `-dead_strip_dylibs` / `-needed_library` / `-needed_framework` for ld64. +The modifier does nothing for linkers that don't support it (e.g. `link.exe`). + +The default for this modifier is unclear, some targets currently specify it as `+as-needed`, some do not. We may want to try making `+as-needed` a default for all targets. diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-bundle.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-bundle.md new file mode 100644 index 0000000000000..ac192cff13a3d --- /dev/null +++ b/src/doc/unstable-book/src/language-features/native-link-modifiers-bundle.md @@ -0,0 +1,19 @@ +# `native_link_modifiers_bundle` + +The tracking issue for this feature is: [#81490] + +[#81490]: https://github.com/rust-lang/rust/issues/81490 + +------------------------ + +The `native_link_modifiers_bundle` feature allows you to use the `bundle` modifier. + +Only compatible with the `static` linking kind. Using any other kind will result in a compiler error. + +`+bundle` means objects from the static library are bundled into the produced crate (a rlib, for example) and are used from this crate later during linking of the final binary. + +`-bundle` means the static library is included into the produced rlib "by name" and object files from it are included only during linking of the final binary, the file search by that name is also performed during final linking. + +This modifier is supposed to supersede the `static-nobundle` linking kind defined by [RFC 1717](https://github.com/rust-lang/rfcs/pull/1717). + +The default for this modifier is currently `+bundle`, but it could be changed later on some future edition boundary. diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-verbatim.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-verbatim.md new file mode 100644 index 0000000000000..02bd87e50956d --- /dev/null +++ b/src/doc/unstable-book/src/language-features/native-link-modifiers-verbatim.md @@ -0,0 +1,20 @@ +# `native_link_modifiers_verbatim` + +The tracking issue for this feature is: [#81490] + +[#81490]: https://github.com/rust-lang/rust/issues/81490 + +------------------------ + +The `native_link_modifiers_verbatim` feature allows you to use the `verbatim` modifier. + +`+verbatim` means that rustc itself won't add any target-specified library prefixes or suffixes (like `lib` or `.a`) to the library name, and will try its best to ask for the same thing from the linker. + +For `ld`-like linkers rustc will use the `-l:filename` syntax (note the colon) when passing the library, so the linker won't add any prefixes or suffixes as well. +See [`-l namespec`](https://sourceware.org/binutils/docs/ld/Options.html) in ld documentation for more details. +For linkers not supporting any verbatim modifiers (e.g. `link.exe` or `ld64`) the library name will be passed as is. + +The default for this modifier is `-verbatim`. + +This RFC changes the behavior of `raw-dylib` linking kind specified by [RFC 2627](https://github.com/rust-lang/rfcs/pull/2627). The `.dll` suffix (or other target-specified suffixes for other targets) is now added automatically. +If your DLL doesn't have the `.dll` suffix, it can be specified with `+verbatim`. diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md b/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md new file mode 100644 index 0000000000000..4961e88cad1e0 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/native-link-modifiers-whole-archive.md @@ -0,0 +1,18 @@ +# `native_link_modifiers_whole_archive` + +The tracking issue for this feature is: [#81490] + +[#81490]: https://github.com/rust-lang/rust/issues/81490 + +------------------------ + +The `native_link_modifiers_whole_archive` feature allows you to use the `whole-archive` modifier. + +Only compatible with the `static` linking kind. Using any other kind will result in a compiler error. + +`+whole-archive` means that the static library is linked as a whole archive without throwing any object files away. + +This modifier translates to `--whole-archive` for `ld`-like linkers, to `/WHOLEARCHIVE` for `link.exe`, and to `-force_load` for `ld64`. +The modifier does nothing for linkers that don't support it. + +The default for this modifier is `-whole-archive`. diff --git a/src/doc/unstable-book/src/language-features/native-link-modifiers.md b/src/doc/unstable-book/src/language-features/native-link-modifiers.md new file mode 100644 index 0000000000000..fc8b575462175 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/native-link-modifiers.md @@ -0,0 +1,11 @@ +# `native_link_modifiers` + +The tracking issue for this feature is: [#81490] + +[#81490]: https://github.com/rust-lang/rust/issues/81490 + +------------------------ + +The `native_link_modifiers` feature allows you to use the `modifiers` syntax with the `#[link(..)]` attribute. + +Modifiers are specified as a comma-delimited string with each modifier prefixed with either a `+` or `-` to indicate that the modifier is enabled or disabled, respectively. The last boolean value specified for a given modifier wins. diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs new file mode 100644 index 0000000000000..2d00aa2a3cfcb --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.rs @@ -0,0 +1,5 @@ +#[link(name = "foo", modifiers = "")] +//~^ ERROR: native link modifiers are experimental +extern "C" {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr new file mode 100644 index 0000000000000..20a2d6a26fa57 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers.stderr @@ -0,0 +1,12 @@ +error[E0658]: native link modifiers are experimental + --> $DIR/feature-gate-native_link_modifiers.rs:1:22 + | +LL | #[link(name = "foo", modifiers = "")] + | ^^^^^^^^^^^^^^ + | + = note: see issue #81490 for more information + = help: add `#![feature(native_link_modifiers)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs new file mode 100644 index 0000000000000..4cf8067592ec2 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.rs @@ -0,0 +1,8 @@ +#![allow(incomplete_features)] +#![feature(native_link_modifiers)] + +#[link(name = "foo", modifiers = "+as-needed")] +//~^ ERROR: `#[link(modifiers="as-needed")]` is unstable +extern "C" {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr new file mode 100644 index 0000000000000..08ce807851b38 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_as_needed.stderr @@ -0,0 +1,12 @@ +error[E0658]: `#[link(modifiers="as-needed")]` is unstable + --> $DIR/feature-gate-native_link_modifiers_as_needed.rs:4:34 + | +LL | #[link(name = "foo", modifiers = "+as-needed")] + | ^^^^^^^^^^^^ + | + = note: see issue #81490 for more information + = help: add `#![feature(native_link_modifiers_as_needed)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs new file mode 100644 index 0000000000000..b2b1dc28e47b9 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.rs @@ -0,0 +1,8 @@ +#![allow(incomplete_features)] +#![feature(native_link_modifiers)] + +#[link(name = "foo", modifiers = "+bundle")] +//~^ ERROR: `#[link(modifiers="bundle")]` is unstable +extern "C" {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr new file mode 100644 index 0000000000000..b3e22b0644aa8 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_bundle.stderr @@ -0,0 +1,12 @@ +error[E0658]: `#[link(modifiers="bundle")]` is unstable + --> $DIR/feature-gate-native_link_modifiers_bundle.rs:4:34 + | +LL | #[link(name = "foo", modifiers = "+bundle")] + | ^^^^^^^^^ + | + = note: see issue #81490 for more information + = help: add `#![feature(native_link_modifiers_bundle)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs new file mode 100644 index 0000000000000..042ce0b3f65b2 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.rs @@ -0,0 +1,8 @@ +#![allow(incomplete_features)] +#![feature(native_link_modifiers)] + +#[link(name = "foo", modifiers = "+verbatim")] +//~^ ERROR: `#[link(modifiers="verbatim")]` is unstable +extern "C" {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr new file mode 100644 index 0000000000000..8159416edfa3d --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_verbatim.stderr @@ -0,0 +1,12 @@ +error[E0658]: `#[link(modifiers="verbatim")]` is unstable + --> $DIR/feature-gate-native_link_modifiers_verbatim.rs:4:34 + | +LL | #[link(name = "foo", modifiers = "+verbatim")] + | ^^^^^^^^^^^ + | + = note: see issue #81490 for more information + = help: add `#![feature(native_link_modifiers_verbatim)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs new file mode 100644 index 0000000000000..ca801e5911432 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.rs @@ -0,0 +1,8 @@ +#![allow(incomplete_features)] +#![feature(native_link_modifiers)] + +#[link(name = "foo", modifiers = "+whole-archive")] +//~^ ERROR: `#[link(modifiers="whole-archive")]` is unstable +extern "C" {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr new file mode 100644 index 0000000000000..cacaa789ecb79 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-native_link_modifiers_whole_archive.stderr @@ -0,0 +1,12 @@ +error[E0658]: `#[link(modifiers="whole-archive")]` is unstable + --> $DIR/feature-gate-native_link_modifiers_whole_archive.rs:4:34 + | +LL | #[link(name = "foo", modifiers = "+whole-archive")] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #81490 for more information + = help: add `#![feature(native_link_modifiers_whole_archive)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr b/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr index d96a48cde9f99..301a1e1341eed 100644 --- a/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr +++ b/src/test/ui/feature-gates/feature-gate-static-nobundle-2.stderr @@ -1,3 +1,5 @@ +warning: library kind `static-nobundle` has been superseded by specifying `-bundle` on library kind `static`. Try `static:-bundle` + error[E0658]: kind="static-nobundle" is unstable | = note: see issue #37403 for more information diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.rs b/src/test/ui/feature-gates/feature-gate-static-nobundle.rs index 05c52f9dbead2..e4bfe8e8e05ca 100644 --- a/src/test/ui/feature-gates/feature-gate-static-nobundle.rs +++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.rs @@ -1,5 +1,6 @@ #[link(name = "foo", kind = "static-nobundle")] -//~^ ERROR: kind="static-nobundle" is unstable +//~^ WARNING: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static` +//~^^ ERROR: kind="static-nobundle" is unstable extern "C" {} fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr index 3a3c86c34295d..9695618207cc9 100644 --- a/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr +++ b/src/test/ui/feature-gates/feature-gate-static-nobundle.stderr @@ -1,3 +1,9 @@ +warning: library kind `static-nobundle` has been superseded by specifying modifier `-bundle` with library kind `static` + --> $DIR/feature-gate-static-nobundle.rs:1:22 + | +LL | #[link(name = "foo", kind = "static-nobundle")] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0658]: kind="static-nobundle" is unstable --> $DIR/feature-gate-static-nobundle.rs:1:1 | @@ -7,6 +13,6 @@ LL | #[link(name = "foo", kind = "static-nobundle")] = note: see issue #37403 for more information = help: add `#![feature(static_nobundle)]` to the crate attributes to enable -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/native-library-link-flags/empty-kind-1.rs b/src/test/ui/native-library-link-flags/empty-kind-1.rs new file mode 100644 index 0000000000000..6f93d38ca93b0 --- /dev/null +++ b/src/test/ui/native-library-link-flags/empty-kind-1.rs @@ -0,0 +1,6 @@ +// Unspecified kind should fail with an error + +// compile-flags: -l =mylib +// error-pattern: unknown library kind ``, expected one of dylib, framework, or static + +fn main() {} diff --git a/src/test/ui/native-library-link-flags/empty-kind-1.stderr b/src/test/ui/native-library-link-flags/empty-kind-1.stderr new file mode 100644 index 0000000000000..2a4a82d538f5b --- /dev/null +++ b/src/test/ui/native-library-link-flags/empty-kind-1.stderr @@ -0,0 +1,2 @@ +error: unknown library kind ``, expected one of dylib, framework, or static + diff --git a/src/test/ui/native-library-link-flags/empty-kind-2.rs b/src/test/ui/native-library-link-flags/empty-kind-2.rs new file mode 100644 index 0000000000000..c0c355770574e --- /dev/null +++ b/src/test/ui/native-library-link-flags/empty-kind-2.rs @@ -0,0 +1,6 @@ +// Unspecified kind should fail with an error + +// compile-flags: -l :+bundle=mylib +// error-pattern: unknown library kind ``, expected one of dylib, framework, or static + +fn main() {} diff --git a/src/test/ui/native-library-link-flags/empty-kind-2.stderr b/src/test/ui/native-library-link-flags/empty-kind-2.stderr new file mode 100644 index 0000000000000..2a4a82d538f5b --- /dev/null +++ b/src/test/ui/native-library-link-flags/empty-kind-2.stderr @@ -0,0 +1,2 @@ +error: unknown library kind ``, expected one of dylib, framework, or static + From 4617b03316dc5816387a748f0f2e1196be28db23 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 5 May 2021 16:00:18 +0800 Subject: [PATCH 9/9] E0583: Include secondary path in error message --- compiler/rustc_expand/src/module.rs | 9 +++++---- src/test/ui/error-codes/E0583.stderr | 2 +- .../invalid-module-declaration.stderr | 2 +- .../missing_non_modrs_mod/missing_non_modrs_mod.stderr | 2 +- .../missing_non_modrs_mod_inline.stderr | 2 +- src/test/ui/parser/mod_file_not_exist.stderr | 2 +- src/test/ui/parser/mod_file_not_exist_windows.stderr | 2 +- src/test/ui/parser/unsafe-mod.stderr | 2 +- src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr | 2 +- 9 files changed, 13 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 993522d01d867..4d777049f0d62 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -36,7 +36,7 @@ crate struct ParsedExternalMod { pub enum ModError<'a> { CircularInclusion(Vec), ModInBlock(Option), - FileNotFound(Ident, PathBuf), + FileNotFound(Ident, PathBuf, PathBuf), MultipleCandidates(Ident, PathBuf, PathBuf), ParserError(DiagnosticBuilder<'a>), } @@ -219,7 +219,7 @@ pub fn default_submod_path<'a>( file_path: secondary_path, dir_ownership: DirOwnership::Owned { relative: None }, }), - (false, false) => Err(ModError::FileNotFound(ident, default_path)), + (false, false) => Err(ModError::FileNotFound(ident, default_path, secondary_path)), (true, true) => Err(ModError::MultipleCandidates(ident, default_path, secondary_path)), } } @@ -247,7 +247,7 @@ impl ModError<'_> { } err } - ModError::FileNotFound(ident, default_path) => { + ModError::FileNotFound(ident, default_path, secondary_path) => { let mut err = struct_span_err!( diag, span, @@ -256,9 +256,10 @@ impl ModError<'_> { ident, ); err.help(&format!( - "to create the module `{}`, create file \"{}\"", + "to create the module `{}`, create file \"{}\" or \"{}\"", ident, default_path.display(), + secondary_path.display(), )); err } diff --git a/src/test/ui/error-codes/E0583.stderr b/src/test/ui/error-codes/E0583.stderr index dbe700355957b..c7bbbf114997d 100644 --- a/src/test/ui/error-codes/E0583.stderr +++ b/src/test/ui/error-codes/E0583.stderr @@ -4,7 +4,7 @@ error[E0583]: file not found for module `module_that_doesnt_exist` LL | mod module_that_doesnt_exist; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs" + = help: to create the module `module_that_doesnt_exist`, create file "$DIR/module_that_doesnt_exist.rs" or "$DIR/module_that_doesnt_exist/mod.rs" error: aborting due to previous error diff --git a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr index 52296042eb4a7..7bc8efd7e4a97 100644 --- a/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr +++ b/src/test/ui/invalid-module-declaration/invalid-module-declaration.stderr @@ -4,7 +4,7 @@ error[E0583]: file not found for module `baz` LL | pub mod baz; | ^^^^^^^^^^^^ | - = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs" + = help: to create the module `baz`, create file "$DIR/auxiliary/foo/bar/baz.rs" or "$DIR/auxiliary/foo/bar/baz/mod.rs" error: aborting due to previous error diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr index 91b3fe15c4be7..31e4206a5463a 100644 --- a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr +++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr @@ -4,7 +4,7 @@ error[E0583]: file not found for module `missing` LL | mod missing; | ^^^^^^^^^^^^ | - = help: to create the module `missing`, create file "$DIR/foo/missing.rs" + = help: to create the module `missing`, create file "$DIR/foo/missing.rs" or "$DIR/foo/missing/mod.rs" error: aborting due to previous error diff --git a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr index f519de46c767f..9d252398b7a14 100644 --- a/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr +++ b/src/test/ui/missing_non_modrs_mod/missing_non_modrs_mod_inline.stderr @@ -4,7 +4,7 @@ error[E0583]: file not found for module `missing` LL | mod missing; | ^^^^^^^^^^^^ | - = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs" + = help: to create the module `missing`, create file "$DIR/foo_inline/inline/missing.rs" or "$DIR/foo_inline/inline/missing/mod.rs" error: aborting due to previous error diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr index 4e08125625f0a..62456d518804f 100644 --- a/src/test/ui/parser/mod_file_not_exist.stderr +++ b/src/test/ui/parser/mod_file_not_exist.stderr @@ -4,7 +4,7 @@ error[E0583]: file not found for module `not_a_real_file` LL | mod not_a_real_file; | ^^^^^^^^^^^^^^^^^^^^ | - = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" + = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" or "$DIR/not_a_real_file/mod.rs" error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist.rs:7:16 diff --git a/src/test/ui/parser/mod_file_not_exist_windows.stderr b/src/test/ui/parser/mod_file_not_exist_windows.stderr index 73cdf098b00c9..d5143dbe982ae 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.stderr +++ b/src/test/ui/parser/mod_file_not_exist_windows.stderr @@ -4,7 +4,7 @@ error[E0583]: file not found for module `not_a_real_file` LL | mod not_a_real_file; | ^^^^^^^^^^^^^^^^^^^^ | - = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" + = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" or "$DIR/not_a_real_file/mod.rs" error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist_windows.rs:7:16 diff --git a/src/test/ui/parser/unsafe-mod.stderr b/src/test/ui/parser/unsafe-mod.stderr index 259b2c1d61e08..dac6e7a355056 100644 --- a/src/test/ui/parser/unsafe-mod.stderr +++ b/src/test/ui/parser/unsafe-mod.stderr @@ -4,7 +4,7 @@ error[E0583]: file not found for module `n` LL | unsafe mod n; | ^^^^^^^^^^^^^ | - = help: to create the module `n`, create file "$DIR/n.rs" + = help: to create the module `n`, create file "$DIR/n.rs" or "$DIR/n/mod.rs" error: module cannot be declared unsafe --> $DIR/unsafe-mod.rs:1:1 diff --git a/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr b/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr index e857a1e60e5fe..dd0dac95e3646 100644 --- a/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr +++ b/src/test/ui/rfc-2457/mod_file_nonascii_forbidden.stderr @@ -4,7 +4,7 @@ error[E0583]: file not found for module `řųśť` LL | mod řųśť; | ^^^^^^^^^ | - = help: to create the module `řųśť`, create file "$DIR/řųśť.rs" + = help: to create the module `řųśť`, create file "$DIR/řųśť.rs" or "$DIR/řųśť/mod.rs" error[E0754]: trying to load file for module `řųśť` with non-ascii identifier name --> $DIR/mod_file_nonascii_forbidden.rs:1:5