From 71285c1da04fe1f046151a9fe10bedfe9aebe3da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 20 Sep 2023 17:00:57 +0000 Subject: [PATCH 1/7] prepare stabilization of modern linker-flavors fix a few comments --- compiler/rustc_session/src/config.rs | 5 ++--- compiler/rustc_target/src/spec/mod.rs | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 3970b751af771..2ea202de820a1 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2758,9 +2758,8 @@ pub fn build_session_options( } // For testing purposes, until we have more feedback about these options: ensure `-Z - // unstable-options` is required when using the unstable `-C link-self-contained` options, like - // `-C link-self-contained=+linker`, and when using the unstable `-C linker-flavor` options, like - // `-C linker-flavor=gnu-lld-cc`. + // unstable-options` is required when using the unstable `-C link-self-contained` and `-C + // linker-flavor` options. if !nightly_options::is_unstable_enabled(matches) { let uses_unstable_self_contained_option = cg.link_self_contained.are_unstable_variants_set(); diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index d4774386e2ed2..16ef78629806f 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -164,11 +164,11 @@ pub enum LinkerFlavor { /// Linker flavors available externally through command line (`-Clinker-flavor`) /// or json target specifications. -/// FIXME: This set has accumulated historically, bring it more in line with the internal -/// linker flavors (`LinkerFlavor`). +/// This set has accumulated historically, and contains both (stable and unstable) legacy values, as +/// well as modern ones matching the internal linker flavors (`LinkerFlavor`). #[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] pub enum LinkerFlavorCli { - // New (unstable) flavors, with direct counterparts in `LinkerFlavor`. + // Modern (unstable) flavors, with direct counterparts in `LinkerFlavor`. Gnu(Cc, Lld), Darwin(Cc, Lld), WasmLld(Cc), @@ -179,7 +179,7 @@ pub enum LinkerFlavorCli { Bpf, Ptx, - // Below: the legacy stable values. + // Legacy stable values Gcc, Ld, Lld(LldFlavor), @@ -504,7 +504,7 @@ linker_flavor_cli_impls! { (LinkerFlavorCli::Bpf) "bpf" (LinkerFlavorCli::Ptx) "ptx" - // Below: legacy stable values + // Legacy stable flavors (LinkerFlavorCli::Gcc) "gcc" (LinkerFlavorCli::Ld) "ld" (LinkerFlavorCli::Lld(LldFlavor::Ld)) "ld.lld" From acc3b61c5e998b8ae170ed7f7b0b37aeecaf01a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 20 Sep 2023 20:04:33 +0000 Subject: [PATCH 2/7] move `LinkSelfContainedComponents` to `rustc_target` --- Cargo.lock | 1 - compiler/rustc_session/Cargo.toml | 1 - compiler/rustc_session/src/config.rs | 36 +-------------------------- compiler/rustc_target/src/spec/mod.rs | 35 ++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 082bb4be93c0a..f7acd49a84cec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4479,7 +4479,6 @@ dependencies = [ name = "rustc_session" version = "0.0.0" dependencies = [ - "bitflags 1.3.2", "getopts", "libc", "rustc_ast", diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index e26d25d9a4123..3af83aaaaa8a2 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -4,7 +4,6 @@ version = "0.0.0" edition = "2021" [dependencies] -bitflags = "1.2.1" getopts = "0.2" rustc_macros = { path = "../rustc_macros" } tracing = "0.1" diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 2ea202de820a1..5e46a86f1ff68 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,6 +12,7 @@ use crate::{EarlyErrorHandler, Session}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; use rustc_target::abi::Align; +use rustc_target::spec::LinkSelfContainedComponents; use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo}; use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS}; @@ -236,41 +237,6 @@ pub struct LinkSelfContained { components: LinkSelfContainedComponents, } -bitflags::bitflags! { - #[derive(Default)] - /// The `-C link-self-contained` components that can individually be enabled or disabled. - pub struct LinkSelfContainedComponents: u8 { - /// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets) - const CRT_OBJECTS = 1 << 0; - /// libc static library (e.g. on `musl`, `wasi` targets) - const LIBC = 1 << 1; - /// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets) - const UNWIND = 1 << 2; - /// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`) - const LINKER = 1 << 3; - /// Sanitizer runtime libraries - const SANITIZERS = 1 << 4; - /// Other MinGW libs and Windows import libs - const MINGW = 1 << 5; - } -} - -impl FromStr for LinkSelfContainedComponents { - type Err = (); - - fn from_str(s: &str) -> Result { - Ok(match s { - "crto" => LinkSelfContainedComponents::CRT_OBJECTS, - "libc" => LinkSelfContainedComponents::LIBC, - "unwind" => LinkSelfContainedComponents::UNWIND, - "linker" => LinkSelfContainedComponents::LINKER, - "sanitizers" => LinkSelfContainedComponents::SANITIZERS, - "mingw" => LinkSelfContainedComponents::MINGW, - _ => return Err(()), - }) - } -} - impl LinkSelfContained { /// Incorporates an enabled or disabled component as specified on the CLI, if possible. /// For example: `+linker`, and `-crto`. diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 16ef78629806f..40d92bd538761 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -520,6 +520,41 @@ impl ToJson for LinkerFlavorCli { } } +bitflags::bitflags! { + #[derive(Default)] + /// The `-C link-self-contained` components that can individually be enabled or disabled. + pub struct LinkSelfContainedComponents: u8 { + /// CRT objects (e.g. on `windows-gnu`, `musl`, `wasi` targets) + const CRT_OBJECTS = 1 << 0; + /// libc static library (e.g. on `musl`, `wasi` targets) + const LIBC = 1 << 1; + /// libgcc/libunwind (e.g. on `windows-gnu`, `fuchsia`, `fortanix`, `gnullvm` targets) + const UNWIND = 1 << 2; + /// Linker, dlltool, and their necessary libraries (e.g. on `windows-gnu` and for `rust-lld`) + const LINKER = 1 << 3; + /// Sanitizer runtime libraries + const SANITIZERS = 1 << 4; + /// Other MinGW libs and Windows import libs + const MINGW = 1 << 5; + } +} + +impl FromStr for LinkSelfContainedComponents { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "crto" => LinkSelfContainedComponents::CRT_OBJECTS, + "libc" => LinkSelfContainedComponents::LIBC, + "unwind" => LinkSelfContainedComponents::UNWIND, + "linker" => LinkSelfContainedComponents::LINKER, + "sanitizers" => LinkSelfContainedComponents::SANITIZERS, + "mingw" => LinkSelfContainedComponents::MINGW, + _ => return Err(()), + }) + } +} + #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] pub enum PanicStrategy { Unwind, From 2ce46f8e8c2efd76973bfa3a068cf67b7b525d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 20 Sep 2023 20:09:06 +0000 Subject: [PATCH 3/7] move single component parsing to dedicated function this will prevent parsing when expecting more than a single component to be parsed, and prepare for the symetric variant-to-name function to be added --- compiler/rustc_session/src/config.rs | 12 ++++++------ compiler/rustc_session/src/options.rs | 2 +- compiler/rustc_target/src/spec/mod.rs | 11 +++++------ 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 5e46a86f1ff68..e3e29669ec572 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -240,21 +240,21 @@ pub struct LinkSelfContained { impl LinkSelfContained { /// Incorporates an enabled or disabled component as specified on the CLI, if possible. /// For example: `+linker`, and `-crto`. - pub(crate) fn handle_cli_component(&mut self, component: &str) -> Result<(), ()> { + pub(crate) fn handle_cli_component(&mut self, component: &str) -> Option<()> { // Note that for example `-Cself-contained=y -Cself-contained=-linker` is not an explicit // set of all values like `y` or `n` used to be. Therefore, if this flag had previously been // set in bulk with its historical values, then manually setting a component clears that // `explicitly_set` state. if let Some(component_to_enable) = component.strip_prefix('+') { self.explicitly_set = None; - self.components.insert(component_to_enable.parse()?); - Ok(()) + self.components.insert(LinkSelfContainedComponents::from_str(component_to_enable)?); + Some(()) } else if let Some(component_to_disable) = component.strip_prefix('-') { self.explicitly_set = None; - self.components.remove(component_to_disable.parse()?); - Ok(()) + self.components.remove(LinkSelfContainedComponents::from_str(component_to_disable)?); + Some(()) } else { - Err(()) + None } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index f7c000c8bd6ed..e8f3123b99edb 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1165,7 +1165,7 @@ mod parse { // 2. Parse a list of enabled and disabled components. for comp in s.split(',') { - if slot.handle_cli_component(comp).is_err() { + if slot.handle_cli_component(comp).is_none() { return false; } } diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 40d92bd538761..5c31c856be4c9 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -539,18 +539,17 @@ bitflags::bitflags! { } } -impl FromStr for LinkSelfContainedComponents { - type Err = (); - - fn from_str(s: &str) -> Result { - Ok(match s { +impl LinkSelfContainedComponents { + /// Parses a single `-Clink-self-contained` well-known component, not a set of flags. + pub fn from_str(s: &str) -> Option { + Some(match s { "crto" => LinkSelfContainedComponents::CRT_OBJECTS, "libc" => LinkSelfContainedComponents::LIBC, "unwind" => LinkSelfContainedComponents::UNWIND, "linker" => LinkSelfContainedComponents::LINKER, "sanitizers" => LinkSelfContainedComponents::SANITIZERS, "mingw" => LinkSelfContainedComponents::MINGW, - _ => return Err(()), + _ => return None, }) } } From 5b9aa26401f13e9023bcc0e480694462f4cf031f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 20 Sep 2023 20:25:17 +0000 Subject: [PATCH 4/7] implement opt out `-Clink-self-contained=-linker` record both enabled and disabled components so that they can be merged with the ones that the target spec will define --- compiler/rustc_codegen_ssa/src/back/link.rs | 7 ++-- compiler/rustc_session/src/config.rs | 42 +++++++++++++++------ 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 464424409c7c2..28a51711b9361 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2978,8 +2978,9 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { } // 1. Implement the "self-contained" part of this feature by adding rustc distribution - // directories to the tool's search path. - if sess.opts.cg.link_self_contained.linker() { + // directories to the tool's search path: + // - if the self-contained linker is enabled on the CLI. + if sess.opts.cg.link_self_contained.is_linker_enabled() { for path in sess.get_tools_search_paths(false) { cmd.arg({ let mut arg = OsString::from("-B"); @@ -2990,7 +2991,7 @@ fn add_lld_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { } // 2. Implement the "linker flavor" part of this feature by asking `cc` to use some kind of - // `lld` as the linker. + // `lld` as the linker. cmd.arg("-fuse-ld=lld"); if !flavor.is_gnu() { diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e3e29669ec572..b0d596253fd28 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -233,8 +233,13 @@ pub struct LinkSelfContained { /// Used for compatibility with the existing opt-in and target inference. pub explicitly_set: Option, - /// The components that are enabled. - components: LinkSelfContainedComponents, + /// The components that are enabled on the CLI, using the `+component` syntax or one of the + /// `true` shorcuts. + enabled_components: LinkSelfContainedComponents, + + /// The components that are disabled on the CLI, using the `-component` syntax or one of the + /// `false` shortcuts. + disabled_components: LinkSelfContainedComponents, } impl LinkSelfContained { @@ -247,11 +252,13 @@ impl LinkSelfContained { // `explicitly_set` state. if let Some(component_to_enable) = component.strip_prefix('+') { self.explicitly_set = None; - self.components.insert(LinkSelfContainedComponents::from_str(component_to_enable)?); + self.enabled_components + .insert(LinkSelfContainedComponents::from_str(component_to_enable)?); Some(()) } else if let Some(component_to_disable) = component.strip_prefix('-') { self.explicitly_set = None; - self.components.remove(LinkSelfContainedComponents::from_str(component_to_disable)?); + self.disabled_components + .insert(LinkSelfContainedComponents::from_str(component_to_disable)?); Some(()) } else { None @@ -262,11 +269,14 @@ impl LinkSelfContained { /// purposes. pub(crate) fn set_all_explicitly(&mut self, enabled: bool) { self.explicitly_set = Some(enabled); - self.components = if enabled { - LinkSelfContainedComponents::all() + + if enabled { + self.enabled_components = LinkSelfContainedComponents::all(); + self.disabled_components = LinkSelfContainedComponents::empty(); } else { - LinkSelfContainedComponents::empty() - }; + self.enabled_components = LinkSelfContainedComponents::empty(); + self.disabled_components = LinkSelfContainedComponents::all(); + } } /// Helper creating a fully enabled `LinkSelfContained` instance. Used in tests. @@ -280,13 +290,21 @@ impl LinkSelfContained { /// components was set individually. This would also require the `-Zunstable-options` flag, to /// be allowed. fn are_unstable_variants_set(&self) -> bool { - let any_component_set = !self.components.is_empty(); + let any_component_set = + !self.enabled_components.is_empty() || !self.disabled_components.is_empty(); self.explicitly_set.is_none() && any_component_set } - /// Returns whether the self-contained linker component is enabled. - pub fn linker(&self) -> bool { - self.components.contains(LinkSelfContainedComponents::LINKER) + /// Returns whether the self-contained linker component was enabled on the CLI, using the + /// `-C link-self-contained=+linker` syntax, or one of the `true` shorcuts. + pub fn is_linker_enabled(&self) -> bool { + self.enabled_components.contains(LinkSelfContainedComponents::LINKER) + } + + /// Returns whether the self-contained linker component was disabled on the CLI, using the + /// `-C link-self-contained=-linker` syntax, or one of the `false` shorcuts. + pub fn is_linker_disabled(&self) -> bool { + self.disabled_components.contains(LinkSelfContainedComponents::LINKER) } } From 6f54cbf754d7183280d89b29627791ddaadd87a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 21 Sep 2023 13:26:41 +0000 Subject: [PATCH 5/7] add `IntoIterator` impl for self-contained linking components --- compiler/rustc_target/src/spec/mod.rs | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 5c31c856be4c9..16f70cf43b3fb 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -552,6 +552,46 @@ impl LinkSelfContainedComponents { _ => return None, }) } + + /// Return the component's name. + /// + /// Returns `None` if the bitflags aren't a singular component (but a mix of multiple flags). + pub fn as_str(self) -> Option<&'static str> { + Some(match self { + LinkSelfContainedComponents::CRT_OBJECTS => "crto", + LinkSelfContainedComponents::LIBC => "libc", + LinkSelfContainedComponents::UNWIND => "unwind", + LinkSelfContainedComponents::LINKER => "linker", + LinkSelfContainedComponents::SANITIZERS => "sanitizers", + LinkSelfContainedComponents::MINGW => "mingw", + _ => return None, + }) + } + + /// Returns an array of all the components. + fn all_components() -> [LinkSelfContainedComponents; 6] { + [ + LinkSelfContainedComponents::CRT_OBJECTS, + LinkSelfContainedComponents::LIBC, + LinkSelfContainedComponents::UNWIND, + LinkSelfContainedComponents::LINKER, + LinkSelfContainedComponents::SANITIZERS, + LinkSelfContainedComponents::MINGW, + ] + } +} + +impl IntoIterator for LinkSelfContainedComponents { + type Item = LinkSelfContainedComponents; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + LinkSelfContainedComponents::all_components() + .into_iter() + .filter(|&s| self.contains(s)) + .collect::>() + .into_iter() + } } #[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)] From 13948747d0ea1729980f0d45157fe4b6683ff715 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 21 Sep 2023 13:27:45 +0000 Subject: [PATCH 6/7] consistency check for self-contained linking components CLI options emit an error if components are both enabled and disabled on the CLI --- compiler/rustc_session/src/config.rs | 24 ++++++++++++++++++++++++ compiler/rustc_session/src/lib.rs | 1 + 2 files changed, 25 insertions(+) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b0d596253fd28..8152ace864294 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -306,6 +306,17 @@ impl LinkSelfContained { pub fn is_linker_disabled(&self) -> bool { self.disabled_components.contains(LinkSelfContainedComponents::LINKER) } + + /// Returns CLI inconsistencies to emit errors: individual components were both enabled and + /// disabled. + fn check_consistency(&self) -> Option { + if self.explicitly_set.is_some() { + None + } else { + let common = self.enabled_components.intersection(self.disabled_components); + if common.is_empty() { None } else { Some(common) } + } + } } /// Used with `-Z assert-incr-state`. @@ -2765,6 +2776,19 @@ pub fn build_session_options( } } + // Check `-C link-self-contained` for consistency: individual components cannot be both enabled + // and disabled at the same time. + if let Some(erroneous_components) = cg.link_self_contained.check_consistency() { + let names: String = erroneous_components + .into_iter() + .map(|c| c.as_str().unwrap()) + .intersperse(", ") + .collect(); + handler.early_error(format!( + "some `-C link-self-contained` components were both enabled and disabled: {names}" + )); + } + let prints = collect_print_requests(handler, &mut cg, &mut unstable_opts, matches); let cg = cg; diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index d6c746a7bd85d..ed6705ec239cf 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -6,6 +6,7 @@ #![feature(option_get_or_insert_default)] #![feature(rustc_attrs)] #![feature(map_many_mut)] +#![feature(iter_intersperse)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] From d634cc5a559ced14f1a9f6bcf4b418e55e1036d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 21 Sep 2023 13:29:04 +0000 Subject: [PATCH 7/7] add test for `-Clink-self-contained` consistency --- .../link-self-contained-consistency.many.stderr | 2 ++ .../link-self-contained-consistency.one.stderr | 2 ++ .../ui/linkage-attr/link-self-contained-consistency.rs | 10 ++++++++++ 3 files changed, 14 insertions(+) create mode 100644 tests/ui/linkage-attr/link-self-contained-consistency.many.stderr create mode 100644 tests/ui/linkage-attr/link-self-contained-consistency.one.stderr create mode 100644 tests/ui/linkage-attr/link-self-contained-consistency.rs diff --git a/tests/ui/linkage-attr/link-self-contained-consistency.many.stderr b/tests/ui/linkage-attr/link-self-contained-consistency.many.stderr new file mode 100644 index 0000000000000..a5fc96b4e0b2b --- /dev/null +++ b/tests/ui/linkage-attr/link-self-contained-consistency.many.stderr @@ -0,0 +1,2 @@ +error: some `-C link-self-contained` components were both enabled and disabled: crto, linker + diff --git a/tests/ui/linkage-attr/link-self-contained-consistency.one.stderr b/tests/ui/linkage-attr/link-self-contained-consistency.one.stderr new file mode 100644 index 0000000000000..5982b7a618e7e --- /dev/null +++ b/tests/ui/linkage-attr/link-self-contained-consistency.one.stderr @@ -0,0 +1,2 @@ +error: some `-C link-self-contained` components were both enabled and disabled: linker + diff --git a/tests/ui/linkage-attr/link-self-contained-consistency.rs b/tests/ui/linkage-attr/link-self-contained-consistency.rs new file mode 100644 index 0000000000000..9be72f559a9c4 --- /dev/null +++ b/tests/ui/linkage-attr/link-self-contained-consistency.rs @@ -0,0 +1,10 @@ +// Checks that self-contained linking components cannot be both enabled and disabled at the same +// time on the CLI. + +// check-fail +// revisions: one many +// [one] compile-flags: -Clink-self-contained=-linker -Clink-self-contained=+linker -Zunstable-options +// [many] compile-flags: -Clink-self-contained=+linker,+crto -Clink-self-contained=-linker,-crto -Zunstable-options +// ignore-tidy-linelength + +fn main() {}