Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit d8a32dd

Browse files
committedAug 14, 2022
rustc_target: Add a compatibility layer to separate internal and user-facing linker flavors
1 parent 801821d commit d8a32dd

File tree

5 files changed

+152
-61
lines changed

5 files changed

+152
-61
lines changed
 

‎compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1236,7 +1236,8 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
12361236

12371237
// linker and linker flavor specified via command line have precedence over what the target
12381238
// specification specifies
1239-
if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), sess.opts.cg.linker_flavor) {
1239+
let linker_flavor = sess.opts.cg.linker_flavor.map(LinkerFlavor::from_cli);
1240+
if let Some(ret) = infer_from(sess, sess.opts.cg.linker.clone(), linker_flavor) {
12401241
return ret;
12411242
}
12421243

‎compiler/rustc_session/src/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1212

1313
use rustc_data_structures::stable_hasher::ToStableHashKey;
1414
use rustc_target::abi::{Align, TargetDataLayout};
15-
use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
15+
use rustc_target::spec::{LinkerFlavorCli, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
1616
use rustc_target::spec::{PanicStrategy, SanitizerSet, TARGETS};
1717

1818
use crate::parse::{CrateCheckConfig, CrateConfig};
@@ -2379,7 +2379,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
23792379
}
23802380
}
23812381

2382-
if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
2382+
if cg.linker_flavor == Some(LinkerFlavorCli::L4Bender)
23832383
&& !nightly_options::is_unstable_enabled(matches)
23842384
{
23852385
early_error(

‎compiler/rustc_session/src/options.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::lint;
55
use crate::search_paths::SearchPath;
66
use crate::utils::NativeLib;
77
use rustc_errors::LanguageIdentifier;
8-
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
8+
use rustc_target::spec::{CodeModel, LinkerFlavorCli, MergeFunctions, PanicStrategy, SanitizerSet};
99
use rustc_target::spec::{
1010
RelocModel, RelroLevel, SplitDebuginfo, StackProtector, TargetTriple, TlsModel,
1111
};
@@ -382,7 +382,7 @@ mod desc {
382382
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
383383
pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
384384
pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
385-
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
385+
pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavorCli::one_of();
386386
pub const parse_optimization_fuel: &str = "crate=integer";
387387
pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`";
388388
pub const parse_instrument_coverage: &str =
@@ -763,8 +763,8 @@ mod parse {
763763
true
764764
}
765765

766-
pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
767-
match v.and_then(LinkerFlavor::from_str) {
766+
pub(crate) fn parse_linker_flavor(slot: &mut Option<LinkerFlavorCli>, v: Option<&str>) -> bool {
767+
match v.and_then(LinkerFlavorCli::from_str) {
768768
Some(lf) => *slot = Some(lf),
769769
_ => return false,
770770
}
@@ -1139,7 +1139,7 @@ options! {
11391139
on C toolchain installed in the system"),
11401140
linker: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
11411141
"system linker to link outputs with"),
1142-
linker_flavor: Option<LinkerFlavor> = (None, parse_linker_flavor, [UNTRACKED],
1142+
linker_flavor: Option<LinkerFlavorCli> = (None, parse_linker_flavor, [UNTRACKED],
11431143
"linker flavor"),
11441144
linker_plugin_lto: LinkerPluginLto = (LinkerPluginLto::Disabled,
11451145
parse_linker_plugin_lto, [TRACKED],

‎compiler/rustc_target/src/spec/mod.rs

Lines changed: 139 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,18 @@ pub enum LinkerFlavor {
102102
BpfLinker,
103103
}
104104

105+
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
106+
pub enum LinkerFlavorCli {
107+
Em,
108+
Gcc,
109+
L4Bender,
110+
Ld,
111+
Msvc,
112+
Lld(LldFlavor),
113+
PtxLinker,
114+
BpfLinker,
115+
}
116+
105117
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
106118
pub enum LldFlavor {
107119
Wasm,
@@ -137,14 +149,37 @@ impl ToJson for LldFlavor {
137149
}
138150
}
139151

140-
impl ToJson for LinkerFlavor {
141-
fn to_json(&self) -> Json {
142-
self.desc().to_json()
152+
impl LinkerFlavor {
153+
pub fn from_cli(cli: LinkerFlavorCli) -> LinkerFlavor {
154+
match cli {
155+
LinkerFlavorCli::Em => LinkerFlavor::Em,
156+
LinkerFlavorCli::Gcc => LinkerFlavor::Gcc,
157+
LinkerFlavorCli::L4Bender => LinkerFlavor::L4Bender,
158+
LinkerFlavorCli::Ld => LinkerFlavor::Ld,
159+
LinkerFlavorCli::Msvc => LinkerFlavor::Msvc,
160+
LinkerFlavorCli::Lld(lld_flavor) => LinkerFlavor::Lld(lld_flavor),
161+
LinkerFlavorCli::PtxLinker => LinkerFlavor::PtxLinker,
162+
LinkerFlavorCli::BpfLinker => LinkerFlavor::BpfLinker,
163+
}
164+
}
165+
166+
fn to_cli(self) -> LinkerFlavorCli {
167+
match self {
168+
LinkerFlavor::Em => LinkerFlavorCli::Em,
169+
LinkerFlavor::Gcc => LinkerFlavorCli::Gcc,
170+
LinkerFlavor::L4Bender => LinkerFlavorCli::L4Bender,
171+
LinkerFlavor::Ld => LinkerFlavorCli::Ld,
172+
LinkerFlavor::Msvc => LinkerFlavorCli::Msvc,
173+
LinkerFlavor::Lld(lld_flavor) => LinkerFlavorCli::Lld(lld_flavor),
174+
LinkerFlavor::PtxLinker => LinkerFlavorCli::PtxLinker,
175+
LinkerFlavor::BpfLinker => LinkerFlavorCli::BpfLinker,
176+
}
143177
}
144178
}
179+
145180
macro_rules! flavor_mappings {
146181
($((($($flavor:tt)*), $string:expr),)*) => (
147-
impl LinkerFlavor {
182+
impl LinkerFlavorCli {
148183
pub const fn one_of() -> &'static str {
149184
concat!("one of: ", $($string, " ",)*)
150185
}
@@ -166,17 +201,23 @@ macro_rules! flavor_mappings {
166201
}
167202

168203
flavor_mappings! {
169-
((LinkerFlavor::Em), "em"),
170-
((LinkerFlavor::Gcc), "gcc"),
171-
((LinkerFlavor::L4Bender), "l4-bender"),
172-
((LinkerFlavor::Ld), "ld"),
173-
((LinkerFlavor::Msvc), "msvc"),
174-
((LinkerFlavor::PtxLinker), "ptx-linker"),
175-
((LinkerFlavor::BpfLinker), "bpf-linker"),
176-
((LinkerFlavor::Lld(LldFlavor::Wasm)), "wasm-ld"),
177-
((LinkerFlavor::Lld(LldFlavor::Ld64)), "ld64.lld"),
178-
((LinkerFlavor::Lld(LldFlavor::Ld)), "ld.lld"),
179-
((LinkerFlavor::Lld(LldFlavor::Link)), "lld-link"),
204+
((LinkerFlavorCli::Em), "em"),
205+
((LinkerFlavorCli::Gcc), "gcc"),
206+
((LinkerFlavorCli::L4Bender), "l4-bender"),
207+
((LinkerFlavorCli::Ld), "ld"),
208+
((LinkerFlavorCli::Msvc), "msvc"),
209+
((LinkerFlavorCli::PtxLinker), "ptx-linker"),
210+
((LinkerFlavorCli::BpfLinker), "bpf-linker"),
211+
((LinkerFlavorCli::Lld(LldFlavor::Wasm)), "wasm-ld"),
212+
((LinkerFlavorCli::Lld(LldFlavor::Ld64)), "ld64.lld"),
213+
((LinkerFlavorCli::Lld(LldFlavor::Ld)), "ld.lld"),
214+
((LinkerFlavorCli::Lld(LldFlavor::Link)), "lld-link"),
215+
}
216+
217+
impl ToJson for LinkerFlavorCli {
218+
fn to_json(&self) -> Json {
219+
self.desc().to_json()
220+
}
180221
}
181222

182223
#[derive(Clone, Copy, Debug, PartialEq, Hash, Encodable, Decodable, HashStable_Generic)]
@@ -467,6 +508,7 @@ impl fmt::Display for LinkOutputKind {
467508
}
468509

469510
pub type LinkArgs = BTreeMap<LinkerFlavor, Vec<StaticCow<str>>>;
511+
pub type LinkArgsCli = BTreeMap<LinkerFlavorCli, Vec<StaticCow<str>>>;
470512

471513
#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
472514
pub enum SplitDebuginfo {
@@ -1159,6 +1201,7 @@ pub struct TargetOptions {
11591201
/// Default linker flavor used if `-C linker-flavor` or `-C linker` are not passed
11601202
/// on the command line. Defaults to `LinkerFlavor::Gcc`.
11611203
pub linker_flavor: LinkerFlavor,
1204+
linker_flavor_json: LinkerFlavorCli,
11621205

11631206
/// Linker to invoke
11641207
pub linker: Option<StaticCow<str>>,
@@ -1169,6 +1212,7 @@ pub struct TargetOptions {
11691212

11701213
/// Linker arguments that are passed *before* any user-defined libraries.
11711214
pub pre_link_args: LinkArgs,
1215+
pre_link_args_json: LinkArgsCli,
11721216
/// Objects to link before and after all other object code.
11731217
pub pre_link_objects: CrtObjects,
11741218
pub post_link_objects: CrtObjects,
@@ -1181,15 +1225,19 @@ pub struct TargetOptions {
11811225
/// user-defined but before post-link objects. Standard platform
11821226
/// libraries that should be always be linked to, usually go here.
11831227
pub late_link_args: LinkArgs,
1228+
late_link_args_json: LinkArgsCli,
11841229
/// Linker arguments used in addition to `late_link_args` if at least one
11851230
/// Rust dependency is dynamically linked.
11861231
pub late_link_args_dynamic: LinkArgs,
1232+
late_link_args_dynamic_json: LinkArgsCli,
11871233
/// Linker arguments used in addition to `late_link_args` if all Rust
11881234
/// dependencies are statically linked.
11891235
pub late_link_args_static: LinkArgs,
1236+
late_link_args_static_json: LinkArgsCli,
11901237
/// Linker arguments that are unconditionally passed *after* any
11911238
/// user-defined libraries.
11921239
pub post_link_args: LinkArgs,
1240+
post_link_args_json: LinkArgsCli,
11931241
/// Optional link script applied to `dylib` and `executable` crate types.
11941242
/// This is a string containing the script, not a path. Can only be applied
11951243
/// to linkers where `linker_is_gnu` is true.
@@ -1496,6 +1544,36 @@ impl TargetOptions {
14961544
fn add_post_link_args(&mut self, flavor: LinkerFlavor, args: &[&'static str]) {
14971545
add_link_args(&mut self.post_link_args, flavor, args);
14981546
}
1547+
1548+
fn update_from_cli(&mut self) {
1549+
self.linker_flavor = LinkerFlavor::from_cli(self.linker_flavor_json);
1550+
for (args, args_json) in [
1551+
(&mut self.pre_link_args, &self.pre_link_args_json),
1552+
(&mut self.late_link_args, &self.late_link_args_json),
1553+
(&mut self.late_link_args_dynamic, &self.late_link_args_dynamic_json),
1554+
(&mut self.late_link_args_static, &self.late_link_args_static_json),
1555+
(&mut self.post_link_args, &self.post_link_args_json),
1556+
] {
1557+
*args = args_json
1558+
.iter()
1559+
.map(|(flavor, args)| (LinkerFlavor::from_cli(*flavor), args.clone()))
1560+
.collect();
1561+
}
1562+
}
1563+
1564+
fn update_to_cli(&mut self) {
1565+
self.linker_flavor_json = self.linker_flavor.to_cli();
1566+
for (args, args_json) in [
1567+
(&self.pre_link_args, &mut self.pre_link_args_json),
1568+
(&self.late_link_args, &mut self.late_link_args_json),
1569+
(&self.late_link_args_dynamic, &mut self.late_link_args_dynamic_json),
1570+
(&self.late_link_args_static, &mut self.late_link_args_static_json),
1571+
(&self.post_link_args, &mut self.post_link_args_json),
1572+
] {
1573+
*args_json =
1574+
args.iter().map(|(flavor, args)| (flavor.to_cli(), args.clone())).collect();
1575+
}
1576+
}
14991577
}
15001578

15011579
impl Default for TargetOptions {
@@ -1511,10 +1589,13 @@ impl Default for TargetOptions {
15111589
abi: "".into(),
15121590
vendor: "unknown".into(),
15131591
linker_flavor: LinkerFlavor::Gcc,
1592+
linker_flavor_json: LinkerFlavorCli::Gcc,
15141593
linker: option_env!("CFG_DEFAULT_LINKER").map(|s| s.into()),
15151594
lld_flavor: LldFlavor::Ld,
15161595
pre_link_args: LinkArgs::new(),
1596+
pre_link_args_json: LinkArgsCli::new(),
15171597
post_link_args: LinkArgs::new(),
1598+
post_link_args_json: LinkArgsCli::new(),
15181599
link_script: None,
15191600
asm_args: cvs![],
15201601
cpu: "generic".into(),
@@ -1555,8 +1636,11 @@ impl Default for TargetOptions {
15551636
post_link_objects_self_contained: Default::default(),
15561637
link_self_contained: LinkSelfContainedDefault::False,
15571638
late_link_args: LinkArgs::new(),
1639+
late_link_args_json: LinkArgsCli::new(),
15581640
late_link_args_dynamic: LinkArgs::new(),
1641+
late_link_args_dynamic_json: LinkArgsCli::new(),
15591642
late_link_args_static: LinkArgs::new(),
1643+
late_link_args_static_json: LinkArgsCli::new(),
15601644
link_env: cvs![],
15611645
link_env_remove: cvs![],
15621646
archive_format: "gnu".into(),
@@ -1926,13 +2010,13 @@ impl Target {
19262010
Some(Ok(()))
19272011
})).unwrap_or(Ok(()))
19282012
} );
1929-
($key_name:ident, LinkerFlavor) => ( {
1930-
let name = (stringify!($key_name)).replace("_", "-");
1931-
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
1932-
match LinkerFlavor::from_str(s) {
2013+
($key_name:ident = $json_name:expr, LinkerFlavor) => ( {
2014+
let name = $json_name;
2015+
obj.remove(name).and_then(|o| o.as_str().and_then(|s| {
2016+
match LinkerFlavorCli::from_str(s) {
19332017
Some(linker_flavor) => base.$key_name = linker_flavor,
19342018
_ => return Some(Err(format!("'{}' is not a valid value for linker-flavor. \
1935-
Use {}", s, LinkerFlavor::one_of()))),
2019+
Use {}", s, LinkerFlavorCli::one_of()))),
19362020
}
19372021
Some(Ok(()))
19382022
})).unwrap_or(Ok(()))
@@ -2013,14 +2097,14 @@ impl Target {
20132097
base.$key_name = args;
20142098
}
20152099
} );
2016-
($key_name:ident, link_args) => ( {
2017-
let name = (stringify!($key_name)).replace("_", "-");
2018-
if let Some(val) = obj.remove(&name) {
2100+
($key_name:ident = $json_name:expr, link_args) => ( {
2101+
let name = $json_name;
2102+
if let Some(val) = obj.remove(name) {
20192103
let obj = val.as_object().ok_or_else(|| format!("{}: expected a \
20202104
JSON object with fields per linker-flavor.", name))?;
2021-
let mut args = LinkArgs::new();
2105+
let mut args = LinkArgsCli::new();
20222106
for (k, v) in obj {
2023-
let flavor = LinkerFlavor::from_str(&k).ok_or_else(|| {
2107+
let flavor = LinkerFlavorCli::from_str(&k).ok_or_else(|| {
20242108
format!("{}: '{}' is not a valid value for linker-flavor. \
20252109
Use 'em', 'gcc', 'ld' or 'msvc'", name, k)
20262110
})?;
@@ -2106,19 +2190,19 @@ impl Target {
21062190
key!(env);
21072191
key!(abi);
21082192
key!(vendor);
2109-
key!(linker_flavor, LinkerFlavor)?;
2193+
key!(linker_flavor_json = "linker-flavor", LinkerFlavor)?;
21102194
key!(linker, optional);
21112195
key!(lld_flavor, LldFlavor)?;
21122196
key!(pre_link_objects = "pre-link-objects", link_objects);
21132197
key!(post_link_objects = "post-link-objects", link_objects);
21142198
key!(pre_link_objects_self_contained = "pre-link-objects-fallback", link_objects);
21152199
key!(post_link_objects_self_contained = "post-link-objects-fallback", link_objects);
21162200
key!(link_self_contained = "crt-objects-fallback", link_self_contained)?;
2117-
key!(pre_link_args, link_args);
2118-
key!(late_link_args, link_args);
2119-
key!(late_link_args_dynamic, link_args);
2120-
key!(late_link_args_static, link_args);
2121-
key!(post_link_args, link_args);
2201+
key!(pre_link_args_json = "pre-link-args", link_args);
2202+
key!(late_link_args_json = "late-link-args", link_args);
2203+
key!(late_link_args_dynamic_json = "late-link-args-dynamic", link_args);
2204+
key!(late_link_args_static_json = "late-link-args-static", link_args);
2205+
key!(post_link_args_json = "post-link-args", link_args);
21222206
key!(link_script, optional);
21232207
key!(link_env, env);
21242208
key!(link_env_remove, list);
@@ -2201,6 +2285,8 @@ impl Target {
22012285
// This can cause unfortunate ICEs later down the line.
22022286
return Err("may not set is_builtin for targets not built-in".into());
22032287
}
2288+
base.update_from_cli();
2289+
22042290
// Each field should have been read using `Json::remove` so any keys remaining are unused.
22052291
let remaining_keys = obj.keys();
22062292
Ok((
@@ -2292,42 +2378,44 @@ impl ToJson for Target {
22922378
fn to_json(&self) -> Json {
22932379
let mut d = serde_json::Map::new();
22942380
let default: TargetOptions = Default::default();
2381+
let mut target = self.clone();
2382+
target.update_to_cli();
22952383

22962384
macro_rules! target_val {
22972385
($attr:ident) => {{
22982386
let name = (stringify!($attr)).replace("_", "-");
2299-
d.insert(name, self.$attr.to_json());
2387+
d.insert(name, target.$attr.to_json());
23002388
}};
23012389
}
23022390

23032391
macro_rules! target_option_val {
23042392
($attr:ident) => {{
23052393
let name = (stringify!($attr)).replace("_", "-");
2306-
if default.$attr != self.$attr {
2307-
d.insert(name, self.$attr.to_json());
2394+
if default.$attr != target.$attr {
2395+
d.insert(name, target.$attr.to_json());
23082396
}
23092397
}};
2310-
($attr:ident, $key_name:expr) => {{
2311-
let name = $key_name;
2312-
if default.$attr != self.$attr {
2313-
d.insert(name.into(), self.$attr.to_json());
2398+
($attr:ident, $json_name:expr) => {{
2399+
let name = $json_name;
2400+
if default.$attr != target.$attr {
2401+
d.insert(name.into(), target.$attr.to_json());
23142402
}
23152403
}};
2316-
(link_args - $attr:ident) => {{
2317-
let name = (stringify!($attr)).replace("_", "-");
2318-
if default.$attr != self.$attr {
2319-
let obj = self
2404+
(link_args - $attr:ident, $json_name:expr) => {{
2405+
let name = $json_name;
2406+
if default.$attr != target.$attr {
2407+
let obj = target
23202408
.$attr
23212409
.iter()
23222410
.map(|(k, v)| (k.desc().to_string(), v.clone()))
23232411
.collect::<BTreeMap<_, _>>();
2324-
d.insert(name, obj.to_json());
2412+
d.insert(name.to_string(), obj.to_json());
23252413
}
23262414
}};
23272415
(env - $attr:ident) => {{
23282416
let name = (stringify!($attr)).replace("_", "-");
2329-
if default.$attr != self.$attr {
2330-
let obj = self
2417+
if default.$attr != target.$attr {
2418+
let obj = target
23312419
.$attr
23322420
.iter()
23332421
.map(|&(ref k, ref v)| format!("{k}={v}"))
@@ -2349,19 +2437,19 @@ impl ToJson for Target {
23492437
target_option_val!(env);
23502438
target_option_val!(abi);
23512439
target_option_val!(vendor);
2352-
target_option_val!(linker_flavor);
2440+
target_option_val!(linker_flavor_json, "linker-flavor");
23532441
target_option_val!(linker);
23542442
target_option_val!(lld_flavor);
23552443
target_option_val!(pre_link_objects);
23562444
target_option_val!(post_link_objects);
23572445
target_option_val!(pre_link_objects_self_contained, "pre-link-objects-fallback");
23582446
target_option_val!(post_link_objects_self_contained, "post-link-objects-fallback");
23592447
target_option_val!(link_self_contained, "crt-objects-fallback");
2360-
target_option_val!(link_args - pre_link_args);
2361-
target_option_val!(link_args - late_link_args);
2362-
target_option_val!(link_args - late_link_args_dynamic);
2363-
target_option_val!(link_args - late_link_args_static);
2364-
target_option_val!(link_args - post_link_args);
2448+
target_option_val!(link_args - pre_link_args_json, "pre-link-args");
2449+
target_option_val!(link_args - late_link_args_json, "late-link-args");
2450+
target_option_val!(link_args - late_link_args_dynamic_json, "late-link-args-dynamic");
2451+
target_option_val!(link_args - late_link_args_static_json, "late-link-args-static");
2452+
target_option_val!(link_args - post_link_args_json, "post-link-args");
23652453
target_option_val!(link_script);
23662454
target_option_val!(env - link_env);
23672455
target_option_val!(link_env_remove);

‎compiler/rustc_target/src/spec/tests/tests_impl.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ use super::super::*;
22
use std::assert_matches::assert_matches;
33

44
// Test target self-consistency and JSON encoding/decoding roundtrip.
5-
pub(super) fn test_target(target: Target) {
5+
pub(super) fn test_target(mut target: Target) {
6+
let recycled_target = Target::from_json(target.to_json()).map(|(j, _)| j);
7+
target.update_to_cli();
68
target.check_consistency();
7-
assert_eq!(Target::from_json(target.to_json()).map(|(j, _)| j), Ok(target));
9+
assert_eq!(recycled_target, Ok(target));
810
}
911

1012
impl Target {

0 commit comments

Comments
 (0)
Please sign in to comment.