diff --git a/RELEASES.md b/RELEASES.md index 024610bc7a417..1f940e6bc2d3b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,151 @@ +Version 1.52.0 (2021-05-06) +============================ + +Language +-------- +- [Added the `unsafe_op_in_unsafe_fn` lint, which checks whether the unsafe code + in an `unsafe fn` is wrapped in a `unsafe` block.][79208] This lint + is allowed by default, and may become a warning or hard error in a + future edition. +- [You can now cast mutable references to arrays to a pointer of the same type as + the element.][81479] + +Compiler +-------- +- [Upgraded the default LLVM to LLVM 12.][81451] + +Added tier 3\* support for the following targets. + +- [`s390x-unknown-linux-musl`][82166] +- [`riscv32gc-unknown-linux-musl` & `riscv64gc-unknown-linux-musl`][82202] +- [`powerpc-unknown-openbsd`][82733] + +\* Refer to Rust's [platform support page][platform-support-doc] for more +information on Rust's tiered platform support. + +Libraries +--------- +- [`OsString` now implements `Extend` and `FromIterator`.][82121] +- [`cmp::Reverse` now has `#[repr(transparent)]` representation.][81879] +- [`Arc` now implements `error::Error`.][80553] +- [All integer division and remainder operations are now `const`.][80962] + +Stabilised APIs +------------- +- [`Arguments::as_str`] +- [`char::MAX`] +- [`char::REPLACEMENT_CHARACTER`] +- [`char::UNICODE_VERSION`] +- [`char::decode_utf16`] +- [`char::from_digit`] +- [`char::from_u32_unchecked`] +- [`char::from_u32`] +- [`slice::partition_point`] +- [`str::rsplit_once`] +- [`str::split_once`] + +The following previously stable APIs are now `const`. + +- [`char::len_utf8`] +- [`char::len_utf16`] +- [`char::to_ascii_uppercase`] +- [`char::to_ascii_lowercase`] +- [`char::eq_ignore_ascii_case`] +- [`u8::to_ascii_uppercase`] +- [`u8::to_ascii_lowercase`] +- [`u8::eq_ignore_ascii_case`] + +Rustdoc +------- +- [Rustdoc lints are now treated as a tool lint, meaning that + lints are now prefixed with `rustdoc::` (e.g. `#[warn(rustdoc::non_autolinks)]`).][80527] + Using the old style is still allowed, and will become a warning in + a future release. +- [Rustdoc now supports argument files.][82261] +- [Rustdoc now generates smart punctuation for documentation.][79423] +- [You can now use "task lists" in Rustdoc Markdown.][81766] E.g. + ```markdown + - [x] Complete + - [ ] Todo + ``` + +Misc +---- +- [You can now pass multiple filters to tests.][81356] E.g. + `cargo test -- foo bar` will run all tests that match `foo` and `bar`. +- [Rustup now distributes PDB symbols for the `std` library on Windows, + allowing you to see `std` symbols when debugging.][82218] + +Internal Only +------------- +These changes provide no direct user facing benefits, but represent significant +improvements to the internals and overall performance of rustc and +related tools. + +- [Check the result cache before the DepGraph when ensuring queries][81855] +- [Try fast_reject::simplify_type in coherence before doing full check][81744] +- [Only store a LocalDefId in some HIR nodes][81611] +- [Store HIR attributes in a side table][79519] + +Compatibility Notes +------------------- +- [Cargo build scripts are now forbidden from setting `RUSTC_BOOTSTRAP`.][cargo/9181] +- [Removed support for the `x86_64-rumprun-netbsd` target.][82594] +- [Deprecated the `x86_64-sun-solaris` target in favor of `x86_64-pc-solaris`.][82216] +- [Rustdoc now only accepts `,`, ` `, and `\t` as delimiters for specifying + languages in code blocks.][78429] +- [Rustc now catches more cases of `pub_use_of_private_extern_crate`][80763] +- [Changes in how proc macros handle whitespace may lead to panics when used + with older `proc-macro-hack` versions. A `cargo update` should be sufficient to fix this in all cases.][84136] + +[84136]: https://github.com/rust-lang/rust/issues/84136 +[80763]: https://github.com/rust-lang/rust/pull/80763 +[82166]: https://github.com/rust-lang/rust/pull/82166 +[82121]: https://github.com/rust-lang/rust/pull/82121 +[81879]: https://github.com/rust-lang/rust/pull/81879 +[82261]: https://github.com/rust-lang/rust/pull/82261 +[82218]: https://github.com/rust-lang/rust/pull/82218 +[82216]: https://github.com/rust-lang/rust/pull/82216 +[82202]: https://github.com/rust-lang/rust/pull/82202 +[81855]: https://github.com/rust-lang/rust/pull/81855 +[81766]: https://github.com/rust-lang/rust/pull/81766 +[81744]: https://github.com/rust-lang/rust/pull/81744 +[81611]: https://github.com/rust-lang/rust/pull/81611 +[81479]: https://github.com/rust-lang/rust/pull/81479 +[81451]: https://github.com/rust-lang/rust/pull/81451 +[81356]: https://github.com/rust-lang/rust/pull/81356 +[80962]: https://github.com/rust-lang/rust/pull/80962 +[80553]: https://github.com/rust-lang/rust/pull/80553 +[80527]: https://github.com/rust-lang/rust/pull/80527 +[79519]: https://github.com/rust-lang/rust/pull/79519 +[79423]: https://github.com/rust-lang/rust/pull/79423 +[79208]: https://github.com/rust-lang/rust/pull/79208 +[78429]: https://github.com/rust-lang/rust/pull/78429 +[82733]: https://github.com/rust-lang/rust/pull/82733 +[82594]: https://github.com/rust-lang/rust/pull/82594 +[cargo/9181]: https://github.com/rust-lang/cargo/pull/9181 +[`char::MAX`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.MAX +[`char::REPLACEMENT_CHARACTER`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.REPLACEMENT_CHARACTER +[`char::UNICODE_VERSION`]: https://doc.rust-lang.org/std/primitive.char.html#associatedconstant.UNICODE_VERSION +[`char::decode_utf16`]: https://doc.rust-lang.org/std/primitive.char.html#method.decode_utf16 +[`char::from_u32`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_u32 +[`char::from_u32_unchecked`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_u32_unchecked +[`char::from_digit`]: https://doc.rust-lang.org/std/primitive.char.html#method.from_digit +[`Peekable::next_if`]: https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if +[`Peekable::next_if_eq`]: https://doc.rust-lang.org/stable/std/iter/struct.Peekable.html#method.next_if_eq +[`Arguments::as_str`]: https://doc.rust-lang.org/stable/std/fmt/struct.Arguments.html#method.as_str +[`str::split_once`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.split_once +[`str::rsplit_once`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.rsplit_once +[`slice::partition_point`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.partition_point +[`char::len_utf8`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.len_utf8 +[`char::len_utf16`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.len_utf16 +[`char::to_ascii_uppercase`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_ascii_uppercase +[`char::to_ascii_lowercase`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.to_ascii_lowercase +[`char::eq_ignore_ascii_case`]: https://doc.rust-lang.org/stable/std/primitive.char.html#method.eq_ignore_ascii_case +[`u8::to_ascii_uppercase`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.to_ascii_uppercase +[`u8::to_ascii_lowercase`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.to_ascii_lowercase +[`u8::eq_ignore_ascii_case`]: https://doc.rust-lang.org/stable/std/primitive.u8.html#method.eq_ignore_ascii_case + Version 1.51.0 (2021-03-25) ============================ 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..401d379b0d161 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); } } @@ -432,8 +462,6 @@ impl<'a> Linker for GccLinker<'a> { // insert it here. if self.sess.target.is_like_osx { self.linker_arg("-dead_strip"); - } else if self.sess.target.is_like_solaris { - self.linker_arg("-zignore"); // If we're building a dylib, we don't use --gc-sections because LLVM // has already done the best it can do, and we also don't want to @@ -445,6 +473,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; @@ -655,6 +693,10 @@ impl<'a> Linker for GccLinker<'a> { fn add_as_needed(&mut self) { if self.sess.target.linker_is_gnu { self.linker_arg("--as-needed"); + } else if self.sess.target.is_like_solaris { + // -z ignore is the Solaris equivalent to the GNU ld --as-needed option + self.linker_arg("-z"); + self.linker_arg("ignore"); } } } @@ -708,8 +750,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 +769,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 +808,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 +963,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 +975,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 +991,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 +1014,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 +1022,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 +1169,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 +1207,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 +1223,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 +1381,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 +1389,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 +1401,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 +1413,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_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 03c83f9c07b5d..f9140609c0f3c 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -464,31 +464,9 @@ impl<'a> StripUnconfigured<'a> { return true; } }; - let error = |span, msg, suggestion: &str| { - let mut err = self.sess.parse_sess.span_diagnostic.struct_span_err(span, msg); - if !suggestion.is_empty() { - err.span_suggestion( - span, - "expected syntax is", - suggestion.into(), - Applicability::MaybeIncorrect, - ); - } - err.emit(); - true - }; - let span = meta_item.span; - match meta_item.meta_item_list() { - None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"), - Some([]) => error(span, "`cfg` predicate is not specified", ""), - Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""), - Some([single]) => match single.meta_item() { - Some(meta_item) => { - attr::cfg_matches(meta_item, &self.sess.parse_sess, self.features) - } - None => error(single.span(), "`cfg` predicate key cannot be a literal", ""), - }, - } + parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| { + attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features) + }) }) } @@ -532,6 +510,32 @@ impl<'a> StripUnconfigured<'a> { } } +pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItem> { + let error = |span, msg, suggestion: &str| { + let mut err = sess.parse_sess.span_diagnostic.struct_span_err(span, msg); + if !suggestion.is_empty() { + err.span_suggestion( + span, + "expected syntax is", + suggestion.into(), + Applicability::HasPlaceholders, + ); + } + err.emit(); + None + }; + let span = meta_item.span; + match meta_item.meta_item_list() { + None => error(span, "`cfg` is not followed by parentheses", "cfg(/* predicate */)"), + Some([]) => error(span, "`cfg` predicate is not specified", ""), + Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""), + Some([single]) => match single.meta_item() { + Some(meta_item) => Some(meta_item), + None => error(single.span(), "`cfg` predicate key cannot be a literal", ""), + }, + } +} + fn is_cfg(sess: &Session, attr: &Attribute) -> bool { sess.check_name(attr, sym::cfg) } 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_mir/src/transform/const_goto.rs b/compiler/rustc_mir/src/transform/const_goto.rs index b5c8b4bebc360..ba10b54c5ae2e 100644 --- a/compiler/rustc_mir/src/transform/const_goto.rs +++ b/compiler/rustc_mir/src/transform/const_goto.rs @@ -47,7 +47,7 @@ impl<'tcx> MirPass<'tcx> for ConstGoto { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(body); + simplify_cfg(tcx, body); simplify_locals(body, tcx); } } diff --git a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs index c41e71e09a4ef..912505c65983e 100644 --- a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs +++ b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs @@ -26,7 +26,7 @@ impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { if has_opts_to_apply { let mut opt_applier = OptApplier { tcx, duplicates }; opt_applier.visit_body(body); - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index f7ea9faec4728..ac39206623308 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -164,7 +164,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { // Since this optimization adds new basic blocks and invalidates others, // clean up the cfg to make it nicer for other passes if should_cleanup { - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index 003003a8abbea..3560b4b1e8645 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -964,7 +964,7 @@ fn create_generator_drop_shim<'tcx>( // Make sure we remove dead blocks to remove // unrelated code from the resume part of the function - simplify::remove_dead_blocks(&mut body); + simplify::remove_dead_blocks(tcx, &mut body); dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(())); @@ -1137,7 +1137,7 @@ fn create_generator_resume_function<'tcx>( // Make sure we remove dead blocks to remove // unrelated code from the drop part of the function - simplify::remove_dead_blocks(body); + simplify::remove_dead_blocks(tcx, body); dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(())); } diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index b6f80763bc8c4..f1c95a84ade85 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -57,7 +57,7 @@ impl<'tcx> MirPass<'tcx> for Inline { if inline(tcx, body) { debug!("running simplify cfg on {:?}", body.source); CfgSimplifier::new(body).simplify(); - remove_dead_blocks(body); + remove_dead_blocks(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index f7a9835353e5c..21b208a08c2dc 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -167,7 +167,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { } if should_cleanup { - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs index 4aaa0baa9f46a..cd2db18055286 100644 --- a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs +++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs @@ -38,6 +38,6 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { } } - simplify::remove_dead_blocks(body) + simplify::remove_dead_blocks(tcx, body) } } diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index 5144d48750de7..02e45021a0aaf 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -36,7 +36,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs index 65e2d096b2094..63373b0cffbb0 100644 --- a/compiler/rustc_mir/src/transform/simplify.rs +++ b/compiler/rustc_mir/src/transform/simplify.rs @@ -29,6 +29,7 @@ use crate::transform::MirPass; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::coverage::*; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; @@ -46,9 +47,9 @@ impl SimplifyCfg { } } -pub fn simplify_cfg(body: &mut Body<'_>) { +pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) { CfgSimplifier::new(body).simplify(); - remove_dead_blocks(body); + remove_dead_blocks(tcx, body); // FIXME: Should probably be moved into some kind of pass manager body.basic_blocks_mut().raw.shrink_to_fit(); @@ -59,9 +60,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg { Cow::Borrowed(&self.label) } - fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source); - simplify_cfg(body); + simplify_cfg(tcx, body); } } @@ -286,7 +287,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { } } -pub fn remove_dead_blocks(body: &mut Body<'_>) { +pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) { let reachable = traversal::reachable_as_bitset(body); let num_blocks = body.basic_blocks().len(); if num_blocks == reachable.count() { @@ -306,6 +307,11 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { } used_blocks += 1; } + + if tcx.sess.instrument_coverage() { + save_unreachable_coverage(basic_blocks, used_blocks); + } + basic_blocks.raw.truncate(used_blocks); for block in basic_blocks { @@ -315,6 +321,32 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { } } +fn save_unreachable_coverage( + basic_blocks: &mut IndexVec>, + first_dead_block: usize, +) { + // retain coverage info for dead blocks, so coverage reports will still + // report `0` executions for the uncovered code regions. + let mut dropped_coverage = Vec::new(); + for dead_block in first_dead_block..basic_blocks.len() { + for statement in basic_blocks[BasicBlock::new(dead_block)].statements.iter() { + if let StatementKind::Coverage(coverage) = &statement.kind { + if let Some(code_region) = &coverage.code_region { + dropped_coverage.push((statement.source_info, code_region.clone())); + } + } + } + } + for (source_info, code_region) in dropped_coverage { + basic_blocks[START_BLOCK].statements.push(Statement { + source_info, + kind: StatementKind::Coverage(box Coverage { + kind: CoverageKind::Unreachable, + code_region: Some(code_region), + }), + }) + } +} pub struct SimplifyLocals; impl<'tcx> MirPass<'tcx> for SimplifyLocals { diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index b42543c04eb3d..c9c4492062720 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -558,7 +558,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranchSame { if did_remove_blocks { // We have dead blocks now, so remove those. - simplify::remove_dead_blocks(body); + simplify::remove_dead_blocks(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs index 658c6b6e9db20..e7fb6b4f6b4ad 100644 --- a/compiler/rustc_mir/src/transform/unreachable_prop.rs +++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs @@ -60,7 +60,7 @@ impl MirPass<'_> for UnreachablePropagation { } if replaced { - simplify::remove_dead_blocks(body); + simplify::remove_dead_blocks(tcx, body); } } } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 1ddd7d694547d..5033f057e0090 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 { impl_dep_tracking_hash_via_hash!(UnstableFeatures); impl_dep_tracking_hash_via_hash!(OutputTypes); impl_dep_tracking_hash_via_hash!(NativeLibKind); + impl_dep_tracking_hash_via_hash!(NativeLib); impl_dep_tracking_hash_via_hash!(SanitizerSet); impl_dep_tracking_hash_via_hash!(CFGuard); impl_dep_tracking_hash_via_hash!(TargetTriple); @@ -2406,8 +2485,8 @@ crate mod dep_tracking { impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); impl_dep_tracking_hash_for_sortable_vec_of!((PathBuf, PathBuf)); impl_dep_tracking_hash_for_sortable_vec_of!(CrateType); + impl_dep_tracking_hash_for_sortable_vec_of!(NativeLib); impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level)); - impl_dep_tracking_hash_for_sortable_vec_of!((String, Option, NativeLibKind)); impl_dep_tracking_hash_for_sortable_vec_of!((String, u64)); impl DepTrackingHash for (T1, T2) 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/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 73e35f0171aa7..b2e4e7a981d20 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -579,6 +579,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let mut restrict_type_params = false; + let mut unsatisfied_bounds = false; if !unsatisfied_predicates.is_empty() { let def_span = |def_id| { self.tcx.sess.source_map().guess_head_span(self.tcx.def_span(def_id)) @@ -739,6 +740,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note(&format!( "the following trait bounds were not satisfied:\n{bound_list}" )); + unsatisfied_bounds = true; } } @@ -752,6 +754,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source, out_of_scope_traits, &unsatisfied_predicates, + unsatisfied_bounds, ); } @@ -984,9 +987,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { source: SelfSource<'tcx>, valid_out_of_scope_traits: Vec, unsatisfied_predicates: &[(ty::Predicate<'tcx>, Option>)], + unsatisfied_bounds: bool, ) { let mut alt_rcvr_sugg = false; - if let SelfSource::MethodCall(rcvr) = source { + if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) { debug!(?span, ?item_name, ?rcvr_ty, ?rcvr); let skippable = [ self.tcx.lang_items().clone_trait(), diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index d7dd7ee02c1f4..0034de9ad1bfa 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -723,7 +723,7 @@ extern "rust-intrinsic" { /// macro, which panics when it is executed, it is *undefined behavior* to /// reach code marked with this function. /// - /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`](crate::hint::unreachable_unchecked). + /// The stabilized version of this intrinsic is [`core::hint::unreachable_unchecked`]. #[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")] pub fn unreachable() -> !; @@ -768,13 +768,13 @@ extern "rust-intrinsic" { /// More specifically, this is the offset in bytes between successive /// items of the same type, including alignment padding. /// - /// The stabilized version of this intrinsic is [`core::mem::size_of`](crate::mem::size_of). + /// The stabilized version of this intrinsic is [`core::mem::size_of`]. #[rustc_const_stable(feature = "const_size_of", since = "1.40.0")] pub fn size_of() -> usize; /// The minimum alignment of a type. /// - /// The stabilized version of this intrinsic is [`core::mem::align_of`](crate::mem::align_of). + /// The stabilized version of this intrinsic is [`core::mem::align_of`]. #[rustc_const_stable(feature = "const_min_align_of", since = "1.40.0")] pub fn min_align_of() -> usize; /// The preferred alignment of a type. @@ -790,13 +790,13 @@ extern "rust-intrinsic" { pub fn size_of_val(_: *const T) -> usize; /// The required alignment of the referenced value. /// - /// The stabilized version of this intrinsic is [`core::mem::align_of_val`](crate::mem::align_of_val). + /// The stabilized version of this intrinsic is [`core::mem::align_of_val`]. #[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")] pub fn min_align_of_val(_: *const T) -> usize; /// Gets a static string slice containing the name of a type. /// - /// The stabilized version of this intrinsic is [`core::any::type_name`](crate::any::type_name). + /// The stabilized version of this intrinsic is [`core::any::type_name`]. #[rustc_const_unstable(feature = "const_type_name", issue = "63084")] pub fn type_name() -> &'static str; @@ -804,7 +804,7 @@ extern "rust-intrinsic" { /// function will return the same value for a type regardless of whichever /// crate it is invoked in. /// - /// The stabilized version of this intrinsic is [`core::any::TypeId::of`](crate::any::TypeId::of). + /// The stabilized version of this intrinsic is [`core::any::TypeId::of`]. #[rustc_const_unstable(feature = "const_type_id", issue = "77125")] pub fn type_id() -> u64; @@ -829,7 +829,7 @@ extern "rust-intrinsic" { /// Gets a reference to a static `Location` indicating where it was called. /// - /// Consider using [`core::panic::Location::caller`](crate::panic::Location::caller) instead. + /// Consider using [`core::panic::Location::caller`] instead. #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] pub fn caller_location() -> &'static crate::panic::Location<'static>; @@ -1158,11 +1158,11 @@ extern "rust-intrinsic" { /// Performs a volatile load from the `src` pointer. /// - /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`](crate::ptr::read_volatile). + /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`]. pub fn volatile_load(src: *const T) -> T; /// Performs a volatile store to the `dst` pointer. /// - /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`](crate::ptr::write_volatile). + /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`]. pub fn volatile_store(dst: *mut T, val: T); /// Performs a volatile load from the `src` pointer @@ -1703,7 +1703,7 @@ extern "rust-intrinsic" { /// Returns the value of the discriminant for the variant in 'v'; /// if `T` has no discriminant, returns `0`. /// - /// The stabilized version of this intrinsic is [`core::mem::discriminant`](crate::mem::discriminant). + /// The stabilized version of this intrinsic is [`core::mem::discriminant`]. #[rustc_const_unstable(feature = "const_discriminant", issue = "69821")] pub fn discriminant_value(v: &T) -> ::Discriminant; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 0e2c140c367a9..cbabf55d17b66 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -169,6 +169,10 @@ #![feature(int_error_matching)] #![deny(unsafe_op_in_unsafe_fn)] +// allow using `core::` in intra-doc links +#[allow(unused_extern_crates)] +extern crate self as core; + #[prelude_import] #[allow(unused)] use prelude::v1::*; diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 415bdde11eb88..2c324b15a1a1a 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -720,9 +720,6 @@ pub const unsafe fn read(src: *const T) -> T { /// /// ## On `packed` structs /// -/// It is currently impossible to create raw pointers to unaligned fields -/// of a packed struct. -/// /// Attempting to create a raw pointer to an `unaligned` struct field with /// an expression such as `&packed.unaligned as *const FieldType` creates an /// intermediate unaligned reference before converting that to a raw pointer. @@ -731,9 +728,13 @@ pub const unsafe fn read(src: *const T) -> T { /// As a result, using `&packed.unaligned as *const FieldType` causes immediate /// *undefined behavior* in your program. /// +/// Instead you must use the [`ptr::addr_of!`](addr_of) macro to +/// create the pointer. You may use that returned pointer together with this +/// function. +/// /// An example of what not to do and how this relates to `read_unaligned` is: /// -/// ```no_run +/// ``` /// #[repr(packed, C)] /// struct Packed { /// _padding: u8, @@ -745,24 +746,15 @@ pub const unsafe fn read(src: *const T) -> T { /// unaligned: 0x01020304, /// }; /// -/// #[allow(unaligned_references)] -/// let v = unsafe { -/// // Here we attempt to take the address of a 32-bit integer which is not aligned. -/// let unaligned = -/// // A temporary unaligned reference is created here which results in -/// // undefined behavior regardless of whether the reference is used or not. -/// &packed.unaligned -/// // Casting to a raw pointer doesn't help; the mistake already happened. -/// as *const u32; +/// // Take the address of a 32-bit integer which is not aligned. +/// // In contrast to `&packed.unaligned as *const _`, this has no undefined behavior. +/// let unaligned = std::ptr::addr_of!(packed.unaligned); /// -/// let v = std::ptr::read_unaligned(unaligned); -/// -/// v -/// }; +/// let v = unsafe { std::ptr::read_unaligned(unaligned) }; +/// assert_eq!(v, 0x01020304); /// ``` /// /// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however. -// FIXME: Update docs based on outcome of RFC #2582 and friends. /// /// # Examples /// @@ -916,9 +908,6 @@ pub const unsafe fn write(dst: *mut T, src: T) { /// /// ## On `packed` structs /// -/// It is currently impossible to create raw pointers to unaligned fields -/// of a packed struct. -/// /// Attempting to create a raw pointer to an `unaligned` struct field with /// an expression such as `&packed.unaligned as *const FieldType` creates an /// intermediate unaligned reference before converting that to a raw pointer. @@ -927,36 +916,32 @@ pub const unsafe fn write(dst: *mut T, src: T) { /// As a result, using `&packed.unaligned as *const FieldType` causes immediate /// *undefined behavior* in your program. /// -/// An example of what not to do and how this relates to `write_unaligned` is: +/// Instead you must use the [`ptr::addr_of_mut!`](addr_of_mut) +/// macro to create the pointer. You may use that returned pointer together with +/// this function. +/// +/// An example of how to do it and how this relates to `write_unaligned` is: /// -/// ```no_run +/// ``` /// #[repr(packed, C)] /// struct Packed { /// _padding: u8, /// unaligned: u32, /// } /// -/// let v = 0x01020304; /// let mut packed: Packed = unsafe { std::mem::zeroed() }; /// -/// #[allow(unaligned_references)] -/// let v = unsafe { -/// // Here we attempt to take the address of a 32-bit integer which is not aligned. -/// let unaligned = -/// // A temporary unaligned reference is created here which results in -/// // undefined behavior regardless of whether the reference is used or not. -/// &mut packed.unaligned -/// // Casting to a raw pointer doesn't help; the mistake already happened. -/// as *mut u32; +/// // Take the address of a 32-bit integer which is not aligned. +/// // In contrast to `&packed.unaligned as *mut _`, this has no undefined behavior. +/// let unaligned = std::ptr::addr_of_mut!(packed.unaligned); /// -/// std::ptr::write_unaligned(unaligned, v); +/// unsafe { std::ptr::write_unaligned(unaligned, 42) }; /// -/// v -/// }; +/// assert_eq!({packed.unaligned}, 42); // `{...}` forces copying the field instead of creating a reference. /// ``` /// -/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however. -// FIXME: Update docs based on outcome of RFC #2582 and friends. +/// Accessing unaligned fields directly with e.g. `packed.unaligned` is safe however +/// (as can be seen in the `assert_eq!` above). /// /// # Examples /// diff --git a/library/core/src/time.rs b/library/core/src/time.rs index bfea39e3211fc..489b722440362 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -518,13 +518,11 @@ impl Duration { if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { let nanos = if self.nanos >= rhs.nanos { self.nanos - rhs.nanos + } else if let Some(sub_secs) = secs.checked_sub(1) { + secs = sub_secs; + self.nanos + NANOS_PER_SEC - rhs.nanos } else { - if let Some(sub_secs) = secs.checked_sub(1) { - secs = sub_secs; - self.nanos + NANOS_PER_SEC - rhs.nanos - } else { - return None; - } + return None; }; debug_assert!(nanos < NANOS_PER_SEC); Some(Duration { secs, nanos }) diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index cd6b0b2d7ee7a..96ab32104ea2c 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -445,7 +445,27 @@ mod prim_unit {} /// Note that here the call to [`drop`] is for clarity - it indicates /// that we are done with the given value and it should be destroyed. /// -/// ## 3. Get it from C. +/// ## 3. Create it using `ptr::addr_of!` +/// +/// Instead of coercing a reference to a raw pointer, you can use the macros +/// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`). +/// These macros allow you to create raw pointers to fields to which you cannot +/// create a reference (without causing undefined behaviour), such as an +/// unaligned field. This might be necessary if packed structs or uninitialized +/// memory is involved. +/// +/// ``` +/// #[derive(Debug, Default, Copy, Clone)] +/// #[repr(C, packed)] +/// struct S { +/// aligned: u8, +/// unaligned: u32, +/// } +/// let s = S::default(); +/// let p = std::ptr::addr_of!(s.unaligned); // not allowed with coercion +/// ``` +/// +/// ## 4. Get it from C. /// /// ``` /// # #![feature(rustc_private)] 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> { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index de9c1882c7d48..03d4223ffa6e0 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -1197,7 +1197,7 @@ note: if you're sure you want to do this, please open an issue as to why. In the .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target })); } - if mode == "run-make" && suite.ends_with("fulldeps") { + if mode == "run-make" && !suite.ends_with("fulldeps") { let rust_demangler = builder .ensure(tool::RustDemangler { compiler, target, extra_features: Vec::new() }) .expect("in-tree tool"); 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/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 5974cd878dd0c..6d05ac073cca3 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -317,10 +317,10 @@ fn merge_attrs( } else { Attributes::from_ast(&both, None) }, - both.cfg(cx.sess().diagnostic()), + both.cfg(cx.sess()), ) } else { - (old_attrs.clean(cx), old_attrs.cfg(cx.sess().diagnostic())) + (old_attrs.clean(cx), old_attrs.cfg(cx.sess())) } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 411cfab9f06a0..e1dde8eeaf84a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2018,7 +2018,7 @@ fn clean_extern_crate( def_id: crate_def_id.into(), visibility: krate.vis.clean(cx), kind: box ExternCrateItem { src: orig_name }, - cfg: attrs.cfg(cx.sess().diagnostic()), + cfg: attrs.cfg(cx.sess()), }] } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 350742e8f2898..a99643d5faeb7 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -444,7 +444,7 @@ impl Item { kind, box ast_attrs.clean(cx), cx, - ast_attrs.cfg(cx.sess().diagnostic()), + ast_attrs.cfg(cx.sess()), ) } @@ -456,7 +456,7 @@ impl Item { cx: &mut DocContext<'_>, cfg: Option>, ) -> Item { - debug!("name={:?}, def_id={:?}", name, def_id); + trace!("name={:?}, def_id={:?}", name, def_id); Item { def_id: def_id.into(), @@ -796,7 +796,7 @@ crate trait AttributesExt { fn other_attrs(&self) -> Vec; - fn cfg(&self, diagnostic: &::rustc_errors::Handler) -> Option>; + fn cfg(&self, sess: &Session) -> Option>; } impl AttributesExt for [ast::Attribute] { @@ -821,17 +821,28 @@ impl AttributesExt for [ast::Attribute] { self.iter().filter(|attr| attr.doc_str().is_none()).cloned().collect() } - fn cfg(&self, diagnostic: &::rustc_errors::Handler) -> Option> { + fn cfg(&self, sess: &Session) -> Option> { let mut cfg = Cfg::True; for attr in self.iter() { + // #[doc] if attr.doc_str().is_none() && attr.has_name(sym::doc) { - if let Some(mi) = attr.meta() { - if let Some(cfg_mi) = Attributes::extract_cfg(&mi) { - // Extracted #[doc(cfg(...))] - match Cfg::parse(cfg_mi) { - Ok(new_cfg) => cfg &= new_cfg, - Err(e) => diagnostic.span_err(e.span, e.msg), + // #[doc(...)] + if let Some(list) = attr.meta().as_ref().and_then(|mi| mi.meta_item_list()) { + for item in list { + // #[doc(include)] + if !item.has_name(sym::cfg) { + continue; + } + // #[doc(cfg(...))] + if let Some(cfg_mi) = item + .meta_item() + .and_then(|item| rustc_expand::config::parse_cfg(&item, sess)) + { + match Cfg::parse(&cfg_mi) { + Ok(new_cfg) => cfg &= new_cfg, + Err(e) => sess.span_err(e.span, e.msg), + } } } } @@ -998,29 +1009,6 @@ impl Attributes { self.other_attrs.lists(name) } - /// Extracts the content from an attribute `#[doc(cfg(content))]`. - crate fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { - use rustc_ast::NestedMetaItem::MetaItem; - - if let ast::MetaItemKind::List(ref nmis) = mi.kind { - if nmis.len() == 1 { - if let MetaItem(ref cfg_mi) = nmis[0] { - if cfg_mi.has_name(sym::cfg) { - if let ast::MetaItemKind::List(ref cfg_nmis) = cfg_mi.kind { - if cfg_nmis.len() == 1 { - if let MetaItem(ref content_mi) = cfg_nmis[0] { - return Some(content_mi); - } - } - } - } - } - } - } - - None - } - /// Reads a `MetaItem` from within an attribute, looks for whether it is a /// `#[doc(include="file")]`, and returns the filename and contents of the file as loaded from /// its expansion. diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index c0157121e1923..e563889f776e5 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1096,7 +1096,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { let ast_attrs = self.tcx.hir().attrs(hir_id); let mut attrs = Attributes::from_ast(ast_attrs, None); - if let Some(ref cfg) = ast_attrs.cfg(self.sess.diagnostic()) { + if let Some(ref cfg) = ast_attrs.cfg(self.sess) { if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) { return; } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 2f3f87215c3a1..e0c1fd06e7b6c 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -155,7 +155,7 @@ impl<'tcx> Context<'tcx> { &self.cache } - fn sess(&self) -> &'tcx Session { + pub(super) fn sess(&self) -> &'tcx Session { &self.shared.tcx.sess } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 70b5458ece894..9d4ac3cf015dd 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -296,7 +296,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl let import_item = clean::Item { def_id: import_def_id.into(), attrs: import_attrs, - cfg: ast_attrs.cfg(cx.tcx().sess.diagnostic()), + cfg: ast_attrs.cfg(cx.sess()), ..myitem.clone() }; diff --git a/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir b/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir deleted file mode 100644 index d1824d189e382..0000000000000 --- a/src/test/run-make-fulldeps/coverage/compiletest-ignore-dir +++ /dev/null @@ -1,3 +0,0 @@ -# Directory "coverage" supports the tests at prefix ../coverage-* - -# Use ./x.py [options] test src/test/run-make-fulldeps/coverage to run all related tests. diff --git a/src/test/run-make-fulldeps/coverage/coverage_tools.mk b/src/test/run-make-fulldeps/coverage/coverage_tools.mk deleted file mode 100644 index aa1dc7b91ce94..0000000000000 --- a/src/test/run-make-fulldeps/coverage/coverage_tools.mk +++ /dev/null @@ -1,6 +0,0 @@ -# Common Makefile include for Rust `run-make-fulldeps/coverage-* tests. Include this -# file with the line: -# -# -include ../coverage/coverage_tools.mk - --include ../tools.mk diff --git a/src/test/run-make-fulldeps/coverage-llvmir/Makefile b/src/test/run-make/coverage-llvmir/Makefile similarity index 100% rename from src/test/run-make-fulldeps/coverage-llvmir/Makefile rename to src/test/run-make/coverage-llvmir/Makefile diff --git a/src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt b/src/test/run-make/coverage-llvmir/filecheck.testprog.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt rename to src/test/run-make/coverage-llvmir/filecheck.testprog.txt diff --git a/src/test/run-make-fulldeps/coverage-llvmir/testprog.rs b/src/test/run-make/coverage-llvmir/testprog.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage-llvmir/testprog.rs rename to src/test/run-make/coverage-llvmir/testprog.rs diff --git a/src/test/run-make-fulldeps/coverage-reports/Makefile b/src/test/run-make/coverage-reports/Makefile similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/Makefile rename to src/test/run-make/coverage-reports/Makefile diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.abort.txt b/src/test/run-make/coverage-reports/expected_show_coverage.abort.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.abort.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.abort.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt b/src/test/run-make/coverage-reports/expected_show_coverage.assert.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.assert.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.assert.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt b/src/test/run-make/coverage-reports/expected_show_coverage.async.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.async.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt b/src/test/run-make/coverage-reports/expected_show_coverage.async2.txt similarity index 99% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.async2.txt index 8a445433ab65f..a8c79efd72356 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt +++ b/src/test/run-make/coverage-reports/expected_show_coverage.async2.txt @@ -12,6 +12,7 @@ 12| 1| if b { 13| 1| println!("non_async_func println in block"); 14| 1| } + ^0 15| 1|} 16| | 17| |// FIXME(#83985): The auto-generated closure in an async function is failing to include diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt b/src/test/run-make/coverage-reports/expected_show_coverage.closure.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.closure.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt b/src/test/run-make/coverage-reports/expected_show_coverage.closure_macro.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.closure_macro.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt b/src/test/run-make/coverage-reports/expected_show_coverage.closure_macro_async.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure_macro_async.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.closure_macro_async.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt b/src/test/run-make/coverage-reports/expected_show_coverage.conditions.txt similarity index 93% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.conditions.txt index 656a26597759d..2d8a98a5d0c92 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt +++ b/src/test/run-make/coverage-reports/expected_show_coverage.conditions.txt @@ -5,6 +5,7 @@ 5| 1| if true { 6| 1| countdown = 10; 7| 1| } + ^0 8| | 9| | const B: u32 = 100; 10| 1| let x = if countdown > 7 { @@ -24,6 +25,7 @@ 24| 1| if true { 25| 1| countdown = 10; 26| 1| } + ^0 27| | 28| 1| if countdown > 7 { 29| 1| countdown -= 4; @@ -42,6 +44,7 @@ 41| 1| if true { 42| 1| countdown = 10; 43| 1| } + ^0 44| | 45| 1| if countdown > 7 { 46| 1| countdown -= 4; @@ -54,13 +57,14 @@ 53| | } else { 54| 0| return; 55| | } - 56| | } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal - 57| | // `true` was const-evaluated. The compiler knows the `if` block will be executed. + 56| 0| } + 57| | 58| | 59| 1| let mut countdown = 0; 60| 1| if true { 61| 1| countdown = 1; 62| 1| } + ^0 63| | 64| 1| let z = if countdown > 7 { ^0 diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.continue.txt b/src/test/run-make/coverage-reports/expected_show_coverage.continue.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.continue.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.continue.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.dead_code.txt b/src/test/run-make/coverage-reports/expected_show_coverage.dead_code.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.dead_code.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.dead_code.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt b/src/test/run-make/coverage-reports/expected_show_coverage.doctest.txt similarity index 98% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.doctest.txt index 1b6bb9ff8891d..7ae0e978808e7 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt +++ b/src/test/run-make/coverage-reports/expected_show_coverage.doctest.txt @@ -9,7 +9,7 @@ 8| 1|//! assert_eq!(1, 1); 9| |//! } else { 10| |//! // this is not! - 11| |//! assert_eq!(1, 2); + 11| 0|//! assert_eq!(1, 2); 12| |//! } 13| 1|//! ``` 14| |//! @@ -84,7 +84,7 @@ 74| 1| if true { 75| 1| assert_eq!(1, 1); 76| | } else { - 77| | assert_eq!(1, 2); + 77| 0| assert_eq!(1, 2); 78| | } 79| 1|} 80| | diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt b/src/test/run-make/coverage-reports/expected_show_coverage.drop_trait.txt similarity index 87% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.drop_trait.txt index fab5be41901c9..fe6a9e93cbf71 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt +++ b/src/test/run-make/coverage-reports/expected_show_coverage.drop_trait.txt @@ -19,11 +19,11 @@ 19| 1| if true { 20| 1| println!("Exiting with error..."); 21| 1| return Err(1); - 22| | } - 23| | - 24| | let _ = Firework { strength: 1000 }; - 25| | - 26| | Ok(()) + 22| 0| } + 23| 0| + 24| 0| let _ = Firework { strength: 1000 }; + 25| 0| + 26| 0| Ok(()) 27| 1|} 28| | 29| |// Expected program output: diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt b/src/test/run-make/coverage-reports/expected_show_coverage.generics.txt similarity index 78% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.generics.txt index 7b38ffb87cba8..8e8bc0fd18943 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt +++ b/src/test/run-make/coverage-reports/expected_show_coverage.generics.txt @@ -52,15 +52,15 @@ 30| 1| if true { 31| 1| println!("Exiting with error..."); 32| 1| return Err(1); - 33| | } // The remaining lines below have no coverage because `if true` (with the constant literal - 34| | // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`. - 35| | // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown - 36| | // in other tests, the lines below would have coverage (which would show they had `0` - 37| | // executions, assuming the condition still evaluated to `true`). - 38| | - 39| | let _ = Firework { strength: 1000 }; - 40| | - 41| | Ok(()) + 33| 0| } + 34| 0| + 35| 0| + 36| 0| + 37| 0| + 38| 0| + 39| 0| let _ = Firework { strength: 1000 }; + 40| 0| + 41| 0| Ok(()) 42| 1|} 43| | 44| |// Expected program output: diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if.txt b/src/test/run-make/coverage-reports/expected_show_coverage.if.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.if.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if_else.txt b/src/test/run-make/coverage-reports/expected_show_coverage.if_else.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.if_else.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.if_else.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline.txt b/src/test/run-make/coverage-reports/expected_show_coverage.inline.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inline.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.inline.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt b/src/test/run-make/coverage-reports/expected_show_coverage.inner_items.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.inner_items.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.inner_items.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-83601.txt b/src/test/run-make/coverage-reports/expected_show_coverage.issue-83601.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-83601.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.issue-83601.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt b/src/test/run-make/coverage-reports/expected_show_coverage.issue-84561.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-84561.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.issue-84561.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.lazy_boolean.txt b/src/test/run-make/coverage-reports/expected_show_coverage.lazy_boolean.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.lazy_boolean.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.lazy_boolean.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loop_break_value.txt b/src/test/run-make/coverage-reports/expected_show_coverage.loop_break_value.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loop_break_value.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.loop_break_value.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt b/src/test/run-make/coverage-reports/expected_show_coverage.loops_branches.txt similarity index 68% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.loops_branches.txt index 81d5c7d90346d..5d572db7cc60d 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt +++ b/src/test/run-make/coverage-reports/expected_show_coverage.loops_branches.txt @@ -9,23 +9,23 @@ 9| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 10| 1| if true { 11| 1| if false { - 12| | while true { - 13| | } + 12| 0| while true { + 13| 0| } 14| 1| } - 15| 1| write!(f, "error")?; - ^0 - 16| | } else { - 17| | } + 15| 1| write!(f, "cool")?; + ^0 + 16| 0| } else { + 17| 0| } 18| | 19| 10| for i in 0..10 { 20| 10| if true { 21| 10| if false { - 22| | while true {} + 22| 0| while true {} 23| 10| } - 24| 10| write!(f, "error")?; - ^0 - 25| | } else { - 26| | } + 24| 10| write!(f, "cool")?; + ^0 + 25| 0| } else { + 26| 0| } 27| | } 28| 1| Ok(()) 29| 1| } @@ -36,21 +36,21 @@ 34| |impl std::fmt::Display for DisplayTest { 35| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 36| 1| if false { - 37| | } else { + 37| 0| } else { 38| 1| if false { - 39| | while true {} + 39| 0| while true {} 40| 1| } - 41| 1| write!(f, "error")?; - ^0 + 41| 1| write!(f, "cool")?; + ^0 42| | } 43| 10| for i in 0..10 { 44| 10| if false { - 45| | } else { + 45| 0| } else { 46| 10| if false { - 47| | while true {} + 47| 0| while true {} 48| 10| } - 49| 10| write!(f, "error")?; - ^0 + 49| 10| write!(f, "cool")?; + ^0 50| | } 51| | } 52| 1| Ok(()) diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.match_or_pattern.txt b/src/test/run-make/coverage-reports/expected_show_coverage.match_or_pattern.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.match_or_pattern.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.match_or_pattern.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.nested_loops.txt b/src/test/run-make/coverage-reports/expected_show_coverage.nested_loops.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.nested_loops.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.nested_loops.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt b/src/test/run-make/coverage-reports/expected_show_coverage.no_cov_crate.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.no_cov_crate.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt b/src/test/run-make/coverage-reports/expected_show_coverage.no_cov_func.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_func.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.no_cov_func.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt b/src/test/run-make/coverage-reports/expected_show_coverage.overflow.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.overflow.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.overflow.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt b/src/test/run-make/coverage-reports/expected_show_coverage.panic_unwind.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.panic_unwind.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.panic_unwind.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt b/src/test/run-make/coverage-reports/expected_show_coverage.partial_eq.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.partial_eq.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.partial_eq.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_loop.txt b/src/test/run-make/coverage-reports/expected_show_coverage.simple_loop.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_loop.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.simple_loop.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt b/src/test/run-make/coverage-reports/expected_show_coverage.simple_match.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.simple_match.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.simple_match.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt b/src/test/run-make/coverage-reports/expected_show_coverage.tight_inf_loop.txt similarity index 75% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.tight_inf_loop.txt index 5adeef7d0850b..2d4c57f451a2d 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt +++ b/src/test/run-make/coverage-reports/expected_show_coverage.tight_inf_loop.txt @@ -1,6 +1,6 @@ 1| 1|fn main() { 2| 1| if false { - 3| | loop {} + 3| 0| loop {} 4| 1| } 5| 1|} diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt b/src/test/run-make/coverage-reports/expected_show_coverage.try_error_result.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.try_error_result.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.try_error_result.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused.txt b/src/test/run-make/coverage-reports/expected_show_coverage.unused.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.unused.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make/coverage-reports/expected_show_coverage.uses_crate.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.uses_crate.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt b/src/test/run-make/coverage-reports/expected_show_coverage.uses_inline_crate.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.uses_inline_crate.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while.txt b/src/test/run-make/coverage-reports/expected_show_coverage.while.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.while.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while_early_ret.txt b/src/test/run-make/coverage-reports/expected_show_coverage.while_early_ret.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.while_early_ret.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.while_early_ret.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt b/src/test/run-make/coverage-reports/expected_show_coverage.yield.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.yield.txt rename to src/test/run-make/coverage-reports/expected_show_coverage.yield.txt diff --git a/src/test/run-make-fulldeps/coverage-reports/normalize_paths.py b/src/test/run-make/coverage-reports/normalize_paths.py similarity index 100% rename from src/test/run-make-fulldeps/coverage-reports/normalize_paths.py rename to src/test/run-make/coverage-reports/normalize_paths.py diff --git a/src/test/run-make-fulldeps/coverage/WARNING_KEEP_NAMES_SHORT.txt b/src/test/run-make/coverage/WARNING_KEEP_NAMES_SHORT.txt similarity index 100% rename from src/test/run-make-fulldeps/coverage/WARNING_KEEP_NAMES_SHORT.txt rename to src/test/run-make/coverage/WARNING_KEEP_NAMES_SHORT.txt diff --git a/src/test/run-make-fulldeps/coverage/abort.rs b/src/test/run-make/coverage/abort.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/abort.rs rename to src/test/run-make/coverage/abort.rs diff --git a/src/test/run-make-fulldeps/coverage/assert.rs b/src/test/run-make/coverage/assert.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/assert.rs rename to src/test/run-make/coverage/assert.rs diff --git a/src/test/run-make-fulldeps/coverage/async.rs b/src/test/run-make/coverage/async.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/async.rs rename to src/test/run-make/coverage/async.rs diff --git a/src/test/run-make-fulldeps/coverage/async2.rs b/src/test/run-make/coverage/async2.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/async2.rs rename to src/test/run-make/coverage/async2.rs diff --git a/src/test/run-make-fulldeps/coverage/closure.rs b/src/test/run-make/coverage/closure.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/closure.rs rename to src/test/run-make/coverage/closure.rs diff --git a/src/test/run-make-fulldeps/coverage/closure_macro.rs b/src/test/run-make/coverage/closure_macro.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/closure_macro.rs rename to src/test/run-make/coverage/closure_macro.rs diff --git a/src/test/run-make-fulldeps/coverage/closure_macro_async.rs b/src/test/run-make/coverage/closure_macro_async.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/closure_macro_async.rs rename to src/test/run-make/coverage/closure_macro_async.rs diff --git a/src/test/run-make/coverage/compiletest-ignore-dir b/src/test/run-make/coverage/compiletest-ignore-dir new file mode 100644 index 0000000000000..b533b272d38cf --- /dev/null +++ b/src/test/run-make/coverage/compiletest-ignore-dir @@ -0,0 +1,3 @@ +# Directory "coverage" supports the tests at prefix ../coverage-* + +# Use ./x.py [options] test src/test/run-make/coverage to run all related tests. diff --git a/src/test/run-make-fulldeps/coverage/conditions.rs b/src/test/run-make/coverage/conditions.rs similarity index 90% rename from src/test/run-make-fulldeps/coverage/conditions.rs rename to src/test/run-make/coverage/conditions.rs index 8a2a0b53e5862..057599d1b471a 100644 --- a/src/test/run-make-fulldeps/coverage/conditions.rs +++ b/src/test/run-make/coverage/conditions.rs @@ -53,8 +53,8 @@ fn main() { } else { return; } - } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal - // `true` was const-evaluated. The compiler knows the `if` block will be executed. + } + let mut countdown = 0; if true { diff --git a/src/test/run-make-fulldeps/coverage/continue.rs b/src/test/run-make/coverage/continue.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/continue.rs rename to src/test/run-make/coverage/continue.rs diff --git a/src/test/run-make/coverage/coverage_tools.mk b/src/test/run-make/coverage/coverage_tools.mk new file mode 100644 index 0000000000000..8fce5f1b958fc --- /dev/null +++ b/src/test/run-make/coverage/coverage_tools.mk @@ -0,0 +1,6 @@ +# Common Makefile include for Rust `run-make/coverage-* tests. Include this +# file with the line: +# +# -include ../coverage/coverage_tools.mk + +-include ../../run-make-fulldeps/tools.mk diff --git a/src/test/run-make-fulldeps/coverage/dead_code.rs b/src/test/run-make/coverage/dead_code.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/dead_code.rs rename to src/test/run-make/coverage/dead_code.rs diff --git a/src/test/run-make-fulldeps/coverage/doctest.rs b/src/test/run-make/coverage/doctest.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/doctest.rs rename to src/test/run-make/coverage/doctest.rs diff --git a/src/test/run-make-fulldeps/coverage/drop_trait.rs b/src/test/run-make/coverage/drop_trait.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/drop_trait.rs rename to src/test/run-make/coverage/drop_trait.rs diff --git a/src/test/run-make-fulldeps/coverage/generics.rs b/src/test/run-make/coverage/generics.rs similarity index 67% rename from src/test/run-make-fulldeps/coverage/generics.rs rename to src/test/run-make/coverage/generics.rs index cbeda35d3b8cf..18b38868496d4 100644 --- a/src/test/run-make-fulldeps/coverage/generics.rs +++ b/src/test/run-make/coverage/generics.rs @@ -30,11 +30,11 @@ fn main() -> Result<(),u8> { if true { println!("Exiting with error..."); return Err(1); - } // The remaining lines below have no coverage because `if true` (with the constant literal - // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`. - // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown - // in other tests, the lines below would have coverage (which would show they had `0` - // executions, assuming the condition still evaluated to `true`). + } + + + + let _ = Firework { strength: 1000 }; diff --git a/src/test/run-make-fulldeps/coverage/if.rs b/src/test/run-make/coverage/if.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/if.rs rename to src/test/run-make/coverage/if.rs diff --git a/src/test/run-make-fulldeps/coverage/if_else.rs b/src/test/run-make/coverage/if_else.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/if_else.rs rename to src/test/run-make/coverage/if_else.rs diff --git a/src/test/run-make-fulldeps/coverage/inline.rs b/src/test/run-make/coverage/inline.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/inline.rs rename to src/test/run-make/coverage/inline.rs diff --git a/src/test/run-make-fulldeps/coverage/inner_items.rs b/src/test/run-make/coverage/inner_items.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/inner_items.rs rename to src/test/run-make/coverage/inner_items.rs diff --git a/src/test/run-make-fulldeps/coverage/issue-83601.rs b/src/test/run-make/coverage/issue-83601.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/issue-83601.rs rename to src/test/run-make/coverage/issue-83601.rs diff --git a/src/test/run-make-fulldeps/coverage/issue-84561.rs b/src/test/run-make/coverage/issue-84561.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/issue-84561.rs rename to src/test/run-make/coverage/issue-84561.rs diff --git a/src/test/run-make-fulldeps/coverage/lazy_boolean.rs b/src/test/run-make/coverage/lazy_boolean.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/lazy_boolean.rs rename to src/test/run-make/coverage/lazy_boolean.rs diff --git a/src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs b/src/test/run-make/coverage/lib/doctest_crate.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/lib/doctest_crate.rs rename to src/test/run-make/coverage/lib/doctest_crate.rs diff --git a/src/test/run-make-fulldeps/coverage/lib/used_crate.rs b/src/test/run-make/coverage/lib/used_crate.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/lib/used_crate.rs rename to src/test/run-make/coverage/lib/used_crate.rs diff --git a/src/test/run-make-fulldeps/coverage/lib/used_inline_crate.rs b/src/test/run-make/coverage/lib/used_inline_crate.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/lib/used_inline_crate.rs rename to src/test/run-make/coverage/lib/used_inline_crate.rs diff --git a/src/test/run-make-fulldeps/coverage/loop_break_value.rs b/src/test/run-make/coverage/loop_break_value.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/loop_break_value.rs rename to src/test/run-make/coverage/loop_break_value.rs diff --git a/src/test/run-make-fulldeps/coverage/loops_branches.rs b/src/test/run-make/coverage/loops_branches.rs similarity index 90% rename from src/test/run-make-fulldeps/coverage/loops_branches.rs rename to src/test/run-make/coverage/loops_branches.rs index 4d9bbad3367f6..7116ce47f4b9d 100644 --- a/src/test/run-make-fulldeps/coverage/loops_branches.rs +++ b/src/test/run-make/coverage/loops_branches.rs @@ -12,7 +12,7 @@ impl std::fmt::Debug for DebugTest { while true { } } - write!(f, "error")?; + write!(f, "cool")?; } else { } @@ -21,7 +21,7 @@ impl std::fmt::Debug for DebugTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } else { } } @@ -38,7 +38,7 @@ impl std::fmt::Display for DisplayTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } for i in 0..10 { if false { @@ -46,7 +46,7 @@ impl std::fmt::Display for DisplayTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } } Ok(()) diff --git a/src/test/run-make-fulldeps/coverage/match_or_pattern.rs b/src/test/run-make/coverage/match_or_pattern.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/match_or_pattern.rs rename to src/test/run-make/coverage/match_or_pattern.rs diff --git a/src/test/run-make-fulldeps/coverage/nested_loops.rs b/src/test/run-make/coverage/nested_loops.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/nested_loops.rs rename to src/test/run-make/coverage/nested_loops.rs diff --git a/src/test/run-make-fulldeps/coverage/no_cov_crate.rs b/src/test/run-make/coverage/no_cov_crate.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/no_cov_crate.rs rename to src/test/run-make/coverage/no_cov_crate.rs diff --git a/src/test/run-make-fulldeps/coverage/no_cov_func.rs b/src/test/run-make/coverage/no_cov_func.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/no_cov_func.rs rename to src/test/run-make/coverage/no_cov_func.rs diff --git a/src/test/run-make-fulldeps/coverage/overflow.rs b/src/test/run-make/coverage/overflow.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/overflow.rs rename to src/test/run-make/coverage/overflow.rs diff --git a/src/test/run-make-fulldeps/coverage/panic_unwind.rs b/src/test/run-make/coverage/panic_unwind.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/panic_unwind.rs rename to src/test/run-make/coverage/panic_unwind.rs diff --git a/src/test/run-make-fulldeps/coverage/partial_eq.rs b/src/test/run-make/coverage/partial_eq.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/partial_eq.rs rename to src/test/run-make/coverage/partial_eq.rs diff --git a/src/test/run-make-fulldeps/coverage/simple_loop.rs b/src/test/run-make/coverage/simple_loop.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/simple_loop.rs rename to src/test/run-make/coverage/simple_loop.rs diff --git a/src/test/run-make-fulldeps/coverage/simple_match.rs b/src/test/run-make/coverage/simple_match.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/simple_match.rs rename to src/test/run-make/coverage/simple_match.rs diff --git a/src/test/run-make-fulldeps/coverage/tight_inf_loop.rs b/src/test/run-make/coverage/tight_inf_loop.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/tight_inf_loop.rs rename to src/test/run-make/coverage/tight_inf_loop.rs diff --git a/src/test/run-make-fulldeps/coverage/try_error_result.rs b/src/test/run-make/coverage/try_error_result.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/try_error_result.rs rename to src/test/run-make/coverage/try_error_result.rs diff --git a/src/test/run-make-fulldeps/coverage/unused.rs b/src/test/run-make/coverage/unused.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/unused.rs rename to src/test/run-make/coverage/unused.rs diff --git a/src/test/run-make-fulldeps/coverage/uses_crate.rs b/src/test/run-make/coverage/uses_crate.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/uses_crate.rs rename to src/test/run-make/coverage/uses_crate.rs diff --git a/src/test/run-make-fulldeps/coverage/uses_inline_crate.rs b/src/test/run-make/coverage/uses_inline_crate.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/uses_inline_crate.rs rename to src/test/run-make/coverage/uses_inline_crate.rs diff --git a/src/test/run-make-fulldeps/coverage/while.rs b/src/test/run-make/coverage/while.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/while.rs rename to src/test/run-make/coverage/while.rs diff --git a/src/test/run-make-fulldeps/coverage/while_early_ret.rs b/src/test/run-make/coverage/while_early_ret.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/while_early_ret.rs rename to src/test/run-make/coverage/while_early_ret.rs diff --git a/src/test/run-make-fulldeps/coverage/yield.rs b/src/test/run-make/coverage/yield.rs similarity index 100% rename from src/test/run-make-fulldeps/coverage/yield.rs rename to src/test/run-make/coverage/yield.rs diff --git a/src/test/rustdoc-ui/invalid-cfg.rs b/src/test/rustdoc-ui/invalid-cfg.rs new file mode 100644 index 0000000000000..d237b8605c068 --- /dev/null +++ b/src/test/rustdoc-ui/invalid-cfg.rs @@ -0,0 +1,4 @@ +#![feature(doc_cfg)] +#[doc(cfg = "x")] //~ ERROR not followed by parentheses +#[doc(cfg(x, y))] //~ ERROR multiple `cfg` predicates +struct S {} diff --git a/src/test/rustdoc-ui/invalid-cfg.stderr b/src/test/rustdoc-ui/invalid-cfg.stderr new file mode 100644 index 0000000000000..dae238b052b8a --- /dev/null +++ b/src/test/rustdoc-ui/invalid-cfg.stderr @@ -0,0 +1,14 @@ +error: `cfg` is not followed by parentheses + --> $DIR/invalid-cfg.rs:2:7 + | +LL | #[doc(cfg = "x")] + | ^^^^^^^^^ help: expected syntax is: `cfg(/* predicate */)` + +error: multiple `cfg` predicates are specified + --> $DIR/invalid-cfg.rs:3:14 + | +LL | #[doc(cfg(x, y))] + | ^ + +error: aborting due to 2 previous errors + diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs index 89a61a289fdeb..1fc80b3e76c53 100644 --- a/src/test/rustdoc/doc-cfg.rs +++ b/src/test/rustdoc/doc-cfg.rs @@ -91,3 +91,11 @@ pub unsafe fn uses_target_feature() { pub fn uses_cfg_target_feature() { uses_target_feature(); } + +// multiple attributes should be allowed +// @has doc_cfg/fn.multiple_attrs.html \ +// '//*[@id="main"]/*[@class="item-info"]/*[@class="stab portability"]' \ +// 'This is supported on x and y and z only.' +#[doc(inline, cfg(x))] +#[doc(cfg(y), cfg(z))] +pub fn multiple_attrs() {} 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 + diff --git a/src/test/ui/suggestions/import-trait-for-method-call.rs b/src/test/ui/suggestions/import-trait-for-method-call.rs index 646f68dea14e8..4dbadbdf98206 100644 --- a/src/test/ui/suggestions/import-trait-for-method-call.rs +++ b/src/test/ui/suggestions/import-trait-for-method-call.rs @@ -6,4 +6,11 @@ fn next_u64() -> u64 { h.finish() //~ ERROR no method named `finish` found for struct `DefaultHasher` } -fn main() {} +trait Bar {} +impl Bar for String {} + +fn main() { + let s = String::from("hey"); + let x: &dyn Bar = &s; + x.as_ref(); //~ ERROR the method `as_ref` exists for reference `&dyn Bar`, but its trait bounds +} diff --git a/src/test/ui/suggestions/import-trait-for-method-call.stderr b/src/test/ui/suggestions/import-trait-for-method-call.stderr index f3ae20552f3d5..a2b9b9d14ab09 100644 --- a/src/test/ui/suggestions/import-trait-for-method-call.stderr +++ b/src/test/ui/suggestions/import-trait-for-method-call.stderr @@ -15,6 +15,22 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f LL | use std::hash::Hasher; | -error: aborting due to previous error +error[E0599]: the method `as_ref` exists for reference `&dyn Bar`, but its trait bounds were not satisfied + --> $DIR/import-trait-for-method-call.rs:15:7 + | +LL | trait Bar {} + | --------- doesn't satisfy `dyn Bar: AsRef<_>` +... +LL | x.as_ref(); + | ^^^^^^ method cannot be called on `&dyn Bar` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `dyn Bar: AsRef<_>` + which is required by `&dyn Bar: AsRef<_>` + = help: items from traits can only be used if the trait is implemented and in scope + = note: the following trait defines an item `as_ref`, perhaps you need to implement it: + candidate #1: `AsRef` + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0599`. 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