Auto merge of #110807 - petrochenkov:strictflavor, r=lqd,wesleywiser
linker: Report linker flavors incompatible with the current target The linker flavor is checked for target compatibility even if linker is never used (e.g. we are producing a rlib). If it causes trouble, we can move the check to `link.rs` so it will run if the linker (flavor) is actually used. And also feature gate explicitly specifying linker flavors for tier 3 targets. The next step is supporting all the internal linker flavors in user-visible interfaces (command line and json).
This commit is contained in:
commit
9af3865dec
13 changed files with 156 additions and 60 deletions
|
@ -23,7 +23,7 @@ use rustc_session::utils::NativeLibKind;
|
||||||
use rustc_session::{filesearch, Session};
|
use rustc_session::{filesearch, Session};
|
||||||
use rustc_span::symbol::Symbol;
|
use rustc_span::symbol::Symbol;
|
||||||
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault};
|
||||||
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy};
|
use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld, PanicStrategy};
|
||||||
use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
|
use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo};
|
||||||
|
|
||||||
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
|
use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder};
|
||||||
|
@ -1302,44 +1302,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
||||||
let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
|
let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
|
||||||
sess.emit_fatal(errors::LinkerFileStem);
|
sess.emit_fatal(errors::LinkerFileStem);
|
||||||
});
|
});
|
||||||
|
let flavor = sess.target.linker_flavor.with_linker_hints(stem);
|
||||||
// Remove any version postfix.
|
|
||||||
let stem = stem
|
|
||||||
.rsplit_once('-')
|
|
||||||
.and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
|
|
||||||
.unwrap_or(stem);
|
|
||||||
|
|
||||||
// GCC/Clang can have an optional target prefix.
|
|
||||||
let flavor = if stem == "emcc" {
|
|
||||||
LinkerFlavor::EmCc
|
|
||||||
} else if stem == "gcc"
|
|
||||||
|| stem.ends_with("-gcc")
|
|
||||||
|| stem == "g++"
|
|
||||||
|| stem.ends_with("-g++")
|
|
||||||
|| stem == "clang"
|
|
||||||
|| stem.ends_with("-clang")
|
|
||||||
|| stem == "clang++"
|
|
||||||
|| stem.ends_with("-clang++")
|
|
||||||
{
|
|
||||||
LinkerFlavor::from_cli(LinkerFlavorCli::Gcc, &sess.target)
|
|
||||||
} else if stem == "wasm-ld" || stem.ends_with("-wasm-ld") {
|
|
||||||
LinkerFlavor::WasmLld(Cc::No)
|
|
||||||
} else if stem == "ld" || stem.ends_with("-ld") {
|
|
||||||
LinkerFlavor::from_cli(LinkerFlavorCli::Ld, &sess.target)
|
|
||||||
} else if stem == "ld.lld" {
|
|
||||||
LinkerFlavor::Gnu(Cc::No, Lld::Yes)
|
|
||||||
} else if stem == "link" {
|
|
||||||
LinkerFlavor::Msvc(Lld::No)
|
|
||||||
} else if stem == "lld-link" {
|
|
||||||
LinkerFlavor::Msvc(Lld::Yes)
|
|
||||||
} else if stem == "lld" || stem == "rust-lld" {
|
|
||||||
let lld_flavor = sess.target.linker_flavor.lld_flavor();
|
|
||||||
LinkerFlavor::from_cli(LinkerFlavorCli::Lld(lld_flavor), &sess.target)
|
|
||||||
} else {
|
|
||||||
// fall back to the value in the target spec
|
|
||||||
sess.target.linker_flavor
|
|
||||||
};
|
|
||||||
|
|
||||||
Some((linker, flavor))
|
Some((linker, flavor))
|
||||||
}
|
}
|
||||||
(None, None) => None,
|
(None, None) => None,
|
||||||
|
@ -1349,7 +1312,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
|
||||||
// linker and linker flavor specified via command line have precedence over what the target
|
// linker and linker flavor specified via command line have precedence over what the target
|
||||||
// specification specifies
|
// specification specifies
|
||||||
let linker_flavor =
|
let linker_flavor =
|
||||||
sess.opts.cg.linker_flavor.map(|flavor| LinkerFlavor::from_cli(flavor, &sess.target));
|
sess.opts.cg.linker_flavor.map(|flavor| sess.target.linker_flavor.with_cli_hints(flavor));
|
||||||
if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) {
|
if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,10 @@ session_feature_gate_error = {$explain}
|
||||||
session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions
|
session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions
|
||||||
|
|
||||||
session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
|
session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
|
||||||
|
|
||||||
|
session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target
|
||||||
|
.note = compatible flavors are: {$compatible_list}
|
||||||
|
|
||||||
session_incorrect_cgu_reuse_type =
|
session_incorrect_cgu_reuse_type =
|
||||||
CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
|
CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
|
||||||
[one] {"at least "}
|
[one] {"at least "}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
|
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
|
||||||
use rustc_target::abi::Align;
|
use rustc_target::abi::Align;
|
||||||
use rustc_target::spec::{PanicStrategy, SanitizerSet, SplitDebuginfo};
|
use rustc_target::spec::{LinkerFlavorCli, PanicStrategy, SanitizerSet, SplitDebuginfo};
|
||||||
use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
|
use rustc_target::spec::{Target, TargetTriple, TargetWarnings, TARGETS};
|
||||||
|
|
||||||
use crate::parse::{CrateCheckConfig, CrateConfig};
|
use crate::parse::{CrateCheckConfig, CrateConfig};
|
||||||
|
@ -2525,6 +2525,19 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(flavor) = cg.linker_flavor {
|
||||||
|
if matches!(flavor, LinkerFlavorCli::BpfLinker | LinkerFlavorCli::PtxLinker)
|
||||||
|
&& !nightly_options::is_unstable_enabled(matches)
|
||||||
|
{
|
||||||
|
let msg = format!(
|
||||||
|
"linker flavor `{}` is unstable, `-Z unstable-options` \
|
||||||
|
flag must also be passed to explicitly use it",
|
||||||
|
flavor.desc()
|
||||||
|
);
|
||||||
|
early_error(error_format, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
|
let prints = collect_print_requests(&mut cg, &mut unstable_opts, matches, error_format);
|
||||||
|
|
||||||
let cg = cg;
|
let cg = cg;
|
||||||
|
|
|
@ -422,3 +422,11 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
|
||||||
pub struct OptimisationFuelExhausted {
|
pub struct OptimisationFuelExhausted {
|
||||||
pub msg: String,
|
pub msg: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(session_incompatible_linker_flavor)]
|
||||||
|
#[note]
|
||||||
|
pub struct IncompatibleLinkerFlavor {
|
||||||
|
pub flavor: &'static str,
|
||||||
|
pub compatible_list: String,
|
||||||
|
}
|
||||||
|
|
|
@ -1675,6 +1675,13 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
||||||
if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray {
|
if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray {
|
||||||
sess.emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() });
|
sess.emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(flavor) = sess.opts.cg.linker_flavor {
|
||||||
|
if let Some(compatible_list) = sess.target.linker_flavor.check_compatibility(flavor) {
|
||||||
|
let flavor = flavor.desc();
|
||||||
|
sess.emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Holds data on the current incremental compilation session, if there is one.
|
/// Holds data on the current incremental compilation session, if there is one.
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#![feature(assert_matches)]
|
#![feature(assert_matches)]
|
||||||
#![feature(associated_type_bounds)]
|
#![feature(associated_type_bounds)]
|
||||||
#![feature(exhaustive_patterns)]
|
#![feature(exhaustive_patterns)]
|
||||||
|
#![feature(iter_intersperse)]
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
|
@ -205,15 +205,11 @@ impl ToJson for LldFlavor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LinkerFlavor {
|
impl LinkerFlavor {
|
||||||
pub fn from_cli(cli: LinkerFlavorCli, target: &TargetOptions) -> LinkerFlavor {
|
/// At this point the target's reference linker flavor doesn't yet exist and we need to infer
|
||||||
Self::from_cli_impl(cli, target.linker_flavor.lld_flavor(), target.linker_flavor.is_gnu())
|
/// it. The inference always succeds and gives some result, and we don't report any flavor
|
||||||
}
|
/// incompatibility errors for json target specs. The CLI flavor is used as the main source
|
||||||
|
/// of truth, other flags are used in case of ambiguities.
|
||||||
/// The passed CLI flavor is preferred over other args coming from the default target spec,
|
fn from_cli_json(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor {
|
||||||
/// so this function can produce a flavor that is incompatible with the current target.
|
|
||||||
/// FIXME: Produce errors when `-Clinker-flavor` is set to something incompatible
|
|
||||||
/// with the current target.
|
|
||||||
fn from_cli_impl(cli: LinkerFlavorCli, lld_flavor: LldFlavor, is_gnu: bool) -> LinkerFlavor {
|
|
||||||
match cli {
|
match cli {
|
||||||
LinkerFlavorCli::Gcc => match lld_flavor {
|
LinkerFlavorCli::Gcc => match lld_flavor {
|
||||||
LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::Yes, Lld::No),
|
LldFlavor::Ld if is_gnu => LinkerFlavor::Gnu(Cc::Yes, Lld::No),
|
||||||
|
@ -257,6 +253,85 @@ impl LinkerFlavor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn infer_cli_hints(cli: LinkerFlavorCli) -> (Option<Cc>, Option<Lld>) {
|
||||||
|
match cli {
|
||||||
|
LinkerFlavorCli::Gcc | LinkerFlavorCli::Em => (Some(Cc::Yes), None),
|
||||||
|
LinkerFlavorCli::Lld(_) => (Some(Cc::No), Some(Lld::Yes)),
|
||||||
|
LinkerFlavorCli::Ld | LinkerFlavorCli::Msvc => (Some(Cc::No), Some(Lld::No)),
|
||||||
|
LinkerFlavorCli::BpfLinker | LinkerFlavorCli::PtxLinker => (None, None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn infer_linker_hints(linker_stem: &str) -> (Option<Cc>, Option<Lld>) {
|
||||||
|
// Remove any version postfix.
|
||||||
|
let stem = linker_stem
|
||||||
|
.rsplit_once('-')
|
||||||
|
.and_then(|(lhs, rhs)| rhs.chars().all(char::is_numeric).then_some(lhs))
|
||||||
|
.unwrap_or(linker_stem);
|
||||||
|
|
||||||
|
// GCC/Clang can have an optional target prefix.
|
||||||
|
if stem == "emcc"
|
||||||
|
|| stem == "gcc"
|
||||||
|
|| stem.ends_with("-gcc")
|
||||||
|
|| stem == "g++"
|
||||||
|
|| stem.ends_with("-g++")
|
||||||
|
|| stem == "clang"
|
||||||
|
|| stem.ends_with("-clang")
|
||||||
|
|| stem == "clang++"
|
||||||
|
|| stem.ends_with("-clang++")
|
||||||
|
{
|
||||||
|
(Some(Cc::Yes), None)
|
||||||
|
} else if stem == "wasm-ld"
|
||||||
|
|| stem.ends_with("-wasm-ld")
|
||||||
|
|| stem == "ld.lld"
|
||||||
|
|| stem == "lld"
|
||||||
|
|| stem == "rust-lld"
|
||||||
|
|| stem == "lld-link"
|
||||||
|
{
|
||||||
|
(Some(Cc::No), Some(Lld::Yes))
|
||||||
|
} else if stem == "ld" || stem.ends_with("-ld") || stem == "link" {
|
||||||
|
(Some(Cc::No), Some(Lld::No))
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_hints(self, (cc_hint, lld_hint): (Option<Cc>, Option<Lld>)) -> LinkerFlavor {
|
||||||
|
match self {
|
||||||
|
LinkerFlavor::Gnu(cc, lld) => {
|
||||||
|
LinkerFlavor::Gnu(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld))
|
||||||
|
}
|
||||||
|
LinkerFlavor::Darwin(cc, lld) => {
|
||||||
|
LinkerFlavor::Darwin(cc_hint.unwrap_or(cc), lld_hint.unwrap_or(lld))
|
||||||
|
}
|
||||||
|
LinkerFlavor::WasmLld(cc) => LinkerFlavor::WasmLld(cc_hint.unwrap_or(cc)),
|
||||||
|
LinkerFlavor::Unix(cc) => LinkerFlavor::Unix(cc_hint.unwrap_or(cc)),
|
||||||
|
LinkerFlavor::Msvc(lld) => LinkerFlavor::Msvc(lld_hint.unwrap_or(lld)),
|
||||||
|
LinkerFlavor::EmCc | LinkerFlavor::Bpf | LinkerFlavor::Ptx => self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_cli_hints(self, cli: LinkerFlavorCli) -> LinkerFlavor {
|
||||||
|
self.with_hints(LinkerFlavor::infer_cli_hints(cli))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_linker_hints(self, linker_stem: &str) -> LinkerFlavor {
|
||||||
|
self.with_hints(LinkerFlavor::infer_linker_hints(linker_stem))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_compatibility(self, cli: LinkerFlavorCli) -> Option<String> {
|
||||||
|
// The CLI flavor should be compatible with the target if it survives this roundtrip.
|
||||||
|
let compatible = |cli| cli == self.with_cli_hints(cli).to_cli();
|
||||||
|
(!compatible(cli)).then(|| {
|
||||||
|
LinkerFlavorCli::all()
|
||||||
|
.iter()
|
||||||
|
.filter(|cli| compatible(**cli))
|
||||||
|
.map(|cli| cli.desc())
|
||||||
|
.intersperse(", ")
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn lld_flavor(self) -> LldFlavor {
|
pub fn lld_flavor(self) -> LldFlavor {
|
||||||
match self {
|
match self {
|
||||||
LinkerFlavor::Gnu(..)
|
LinkerFlavor::Gnu(..)
|
||||||
|
@ -278,6 +353,10 @@ impl LinkerFlavor {
|
||||||
macro_rules! linker_flavor_cli_impls {
|
macro_rules! linker_flavor_cli_impls {
|
||||||
($(($($flavor:tt)*) $string:literal)*) => (
|
($(($($flavor:tt)*) $string:literal)*) => (
|
||||||
impl LinkerFlavorCli {
|
impl LinkerFlavorCli {
|
||||||
|
const fn all() -> &'static [LinkerFlavorCli] {
|
||||||
|
&[$($($flavor)*,)*]
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn one_of() -> &'static str {
|
pub const fn one_of() -> &'static str {
|
||||||
concat!("one of: ", $($string, " ",)*)
|
concat!("one of: ", $($string, " ",)*)
|
||||||
}
|
}
|
||||||
|
@ -289,8 +368,8 @@ macro_rules! linker_flavor_cli_impls {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn desc(&self) -> &str {
|
pub fn desc(self) -> &'static str {
|
||||||
match *self {
|
match self {
|
||||||
$($($flavor)* => $string,)*
|
$($($flavor)* => $string,)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1801,7 +1880,7 @@ impl TargetOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_from_cli(&mut self) {
|
fn update_from_cli(&mut self) {
|
||||||
self.linker_flavor = LinkerFlavor::from_cli_impl(
|
self.linker_flavor = LinkerFlavor::from_cli_json(
|
||||||
self.linker_flavor_json,
|
self.linker_flavor_json,
|
||||||
self.lld_flavor_json,
|
self.lld_flavor_json,
|
||||||
self.linker_is_gnu_json,
|
self.linker_is_gnu_json,
|
||||||
|
@ -1815,12 +1894,7 @@ impl TargetOptions {
|
||||||
] {
|
] {
|
||||||
args.clear();
|
args.clear();
|
||||||
for (flavor, args_json) in args_json {
|
for (flavor, args_json) in args_json {
|
||||||
// Cannot use `from_cli` due to borrow checker.
|
let linker_flavor = self.linker_flavor.with_cli_hints(*flavor);
|
||||||
let linker_flavor = LinkerFlavor::from_cli_impl(
|
|
||||||
*flavor,
|
|
||||||
self.lld_flavor_json,
|
|
||||||
self.linker_is_gnu_json,
|
|
||||||
);
|
|
||||||
// Normalize to no lld to avoid asserts.
|
// Normalize to no lld to avoid asserts.
|
||||||
let linker_flavor = match linker_flavor {
|
let linker_flavor = match linker_flavor {
|
||||||
LinkerFlavor::Gnu(cc, _) => LinkerFlavor::Gnu(cc, Lld::No),
|
LinkerFlavor::Gnu(cc, _) => LinkerFlavor::Gnu(cc, Lld::No),
|
||||||
|
|
6
tests/ui/linkage-attr/incompatible-flavor.rs
Normal file
6
tests/ui/linkage-attr/incompatible-flavor.rs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
// compile-flags: --target=x86_64-unknown-linux-gnu -C linker-flavor=msvc --crate-type=rlib
|
||||||
|
// error-pattern: linker flavor `msvc` is incompatible with the current target
|
||||||
|
// needs-llvm-components:
|
||||||
|
|
||||||
|
#![feature(no_core)]
|
||||||
|
#![no_core]
|
6
tests/ui/linkage-attr/incompatible-flavor.stderr
Normal file
6
tests/ui/linkage-attr/incompatible-flavor.stderr
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
error: linker flavor `msvc` is incompatible with the current target
|
||||||
|
|
|
||||||
|
= note: compatible flavors are: gcc, ld, ld.lld
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// build-fail
|
// build-fail
|
||||||
// dont-check-compiler-stderr
|
// dont-check-compiler-stderr
|
||||||
// compile-flags: -C linker=llllll -C linker-flavor=ld
|
// compile-flags: -C linker=llllll
|
||||||
// error-pattern: `llllll`
|
// error-pattern: `llllll`
|
||||||
|
|
||||||
// Before, the error-pattern checked for "not found". On WSL with appendWindowsPath=true, running
|
// Before, the error-pattern checked for "not found". On WSL with appendWindowsPath=true, running
|
||||||
|
|
2
tests/ui/linkage-attr/unstable-flavor.bpf.stderr
Normal file
2
tests/ui/linkage-attr/unstable-flavor.bpf.stderr
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
error: linker flavor `bpf-linker` is unstable, `-Z unstable-options` flag must also be passed to explicitly use it
|
||||||
|
|
2
tests/ui/linkage-attr/unstable-flavor.ptx.stderr
Normal file
2
tests/ui/linkage-attr/unstable-flavor.ptx.stderr
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
error: linker flavor `ptx-linker` is unstable, `-Z unstable-options` flag must also be passed to explicitly use it
|
||||||
|
|
10
tests/ui/linkage-attr/unstable-flavor.rs
Normal file
10
tests/ui/linkage-attr/unstable-flavor.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// revisions: bpf ptx
|
||||||
|
// [bpf] compile-flags: --target=bpfel-unknown-none -C linker-flavor=bpf-linker --crate-type=rlib
|
||||||
|
// [bpf] error-pattern: linker flavor `bpf-linker` is unstable, `-Z unstable-options` flag
|
||||||
|
// [bpf] needs-llvm-components:
|
||||||
|
// [ptx] compile-flags: --target=nvptx64-nvidia-cuda -C linker-flavor=ptx-linker --crate-type=rlib
|
||||||
|
// [ptx] error-pattern: linker flavor `ptx-linker` is unstable, `-Z unstable-options` flag
|
||||||
|
// [ptx] needs-llvm-components:
|
||||||
|
|
||||||
|
#![feature(no_core)]
|
||||||
|
#![no_core]
|
Loading…
Add table
Add a link
Reference in a new issue