@@ -362,9 +362,14 @@ impl LinkSelfContained {
362
362
/// components was set individually. This would also require the `-Zunstable-options` flag, to
363
363
/// be allowed.
364
364
fn are_unstable_variants_set ( & self ) -> bool {
365
- let any_component_set =
366
- !self . enabled_components . is_empty ( ) || !self . disabled_components . is_empty ( ) ;
367
- self . explicitly_set . is_none ( ) && any_component_set
365
+ if self . explicitly_set . is_some ( ) {
366
+ return false ;
367
+ }
368
+
369
+ // Only the linker component is stable, anything else is thus unstable.
370
+ let mentioned_components = self . enabled_components . union ( self . disabled_components ) ;
371
+ let unstable_components = mentioned_components - LinkSelfContainedComponents :: LINKER ;
372
+ !unstable_components. is_empty ( )
368
373
}
369
374
370
375
/// Returns whether the self-contained linker component was enabled on the CLI, using the
@@ -391,7 +396,7 @@ impl LinkSelfContained {
391
396
}
392
397
}
393
398
394
- /// The different values that `-Z linker-features` can take on the CLI: a list of individually
399
+ /// The different values that `-C linker-features` can take on the CLI: a list of individually
395
400
/// enabled or disabled features used during linking.
396
401
///
397
402
/// There is no need to enable or disable them in bulk. Each feature is fine-grained, and can be
@@ -431,6 +436,44 @@ impl LinkerFeaturesCli {
431
436
_ => None ,
432
437
}
433
438
}
439
+
440
+ /// When *not* using `-Z unstable-options` on the CLI, ensure only stable linker features are
441
+ /// used, for the given `TargetTuple`. Returns `Ok` if no unstable variants are used.
442
+ /// The caller should ensure that e.g. `nightly_options::is_unstable_enabled()`
443
+ /// returns false.
444
+ pub ( crate ) fn check_unstable_variants ( & self , target_tuple : & TargetTuple ) -> Result < ( ) , String > {
445
+ // `-C linker-features=[-+]lld` is only stable on x64 linux.
446
+ let check_lld = |features : LinkerFeatures , polarity : & str | {
447
+ let has_lld = features. is_lld_enabled ( ) ;
448
+ if has_lld && target_tuple. tuple ( ) != "x86_64-unknown-linux-gnu" {
449
+ return Err ( format ! (
450
+ "`-C linker-features={polarity}lld` is unstable on the `{target_tuple}` \
451
+ target. The `-Z unstable-options` flag must also be passed to use it on this target",
452
+ ) ) ;
453
+ }
454
+ Ok ( ( ) )
455
+ } ;
456
+ check_lld ( self . enabled , "+" ) ?;
457
+ check_lld ( self . disabled , "-" ) ?;
458
+
459
+ // Since only lld is stable, any non-lld feature used is unstable, and that's an error.
460
+ let unstable_enabled = self . enabled - LinkerFeatures :: LLD ;
461
+ let unstable_disabled = self . disabled - LinkerFeatures :: LLD ;
462
+ if !unstable_enabled. union ( unstable_disabled) . is_empty ( ) {
463
+ let unstable_features: Vec < _ > = unstable_enabled
464
+ . iter ( )
465
+ . map ( |f| format ! ( "+{}" , f. as_str( ) . unwrap( ) ) )
466
+ . chain ( unstable_disabled. iter ( ) . map ( |f| format ! ( "-{}" , f. as_str( ) . unwrap( ) ) ) )
467
+ . collect ( ) ;
468
+ return Err ( format ! (
469
+ "the requested `-C linker-features={}` are unstable, and also require the \
470
+ `-Z unstable-options` flag to be usable",
471
+ unstable_features. join( "," ) ,
472
+ ) ) ;
473
+ }
474
+
475
+ Ok ( ( ) )
476
+ }
434
477
}
435
478
436
479
/// Used with `-Z assert-incr-state`.
@@ -2486,9 +2529,8 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
2486
2529
}
2487
2530
}
2488
2531
2489
- if !nightly_options:: is_unstable_enabled ( matches)
2490
- && cg. force_frame_pointers == FramePointer :: NonLeaf
2491
- {
2532
+ let unstable_options_enabled = nightly_options:: is_unstable_enabled ( matches) ;
2533
+ if !unstable_options_enabled && cg. force_frame_pointers == FramePointer :: NonLeaf {
2492
2534
early_dcx. early_fatal (
2493
2535
"`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
2494
2536
and a nightly compiler",
@@ -2498,12 +2540,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
2498
2540
// For testing purposes, until we have more feedback about these options: ensure `-Z
2499
2541
// unstable-options` is required when using the unstable `-C link-self-contained` and `-C
2500
2542
// linker-flavor` options.
2501
- if !nightly_options :: is_unstable_enabled ( matches ) {
2543
+ if !unstable_options_enabled {
2502
2544
let uses_unstable_self_contained_option =
2503
2545
cg. link_self_contained . are_unstable_variants_set ( ) ;
2504
2546
if uses_unstable_self_contained_option {
2505
2547
early_dcx. early_fatal (
2506
- "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \
2548
+ "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker`/`+linker` are stable, \
2507
2549
the `-Z unstable-options` flag must also be passed to use the unstable values",
2508
2550
) ;
2509
2551
}
@@ -2546,6 +2588,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
2546
2588
let debuginfo = select_debuginfo ( matches, & cg) ;
2547
2589
let debuginfo_compression = unstable_opts. debuginfo_compression ;
2548
2590
2591
+ if !unstable_options_enabled {
2592
+ if let Err ( error) = cg. linker_features . check_unstable_variants ( & target_triple) {
2593
+ early_dcx. early_fatal ( error) ;
2594
+ }
2595
+ }
2596
+
2549
2597
let crate_name = matches. opt_str ( "crate-name" ) ;
2550
2598
let unstable_features = UnstableFeatures :: from_environment ( crate_name. as_deref ( ) ) ;
2551
2599
// Parse any `-l` flags, which link to native libraries.
0 commit comments