@@ -367,12 +367,40 @@ impl LinkSelfContained {
367367 }
368368
369369 /// To help checking CLI usage while some of the values are unstable: returns whether one of the
370- /// components was set individually. This would also require the `-Zunstable-options` flag, to
371- /// be allowed.
372- fn are_unstable_variants_set ( & self ) -> bool {
373- let any_component_set =
374- !self . enabled_components . is_empty ( ) || !self . disabled_components . is_empty ( ) ;
375- self . explicitly_set . is_none ( ) && any_component_set
370+ /// unstable components was set individually, for the given `TargetTuple`. This would also
371+ /// require the `-Zunstable-options` flag, to be allowed.
372+ fn check_unstable_variants ( & self , target_tuple : & TargetTuple ) -> Result < ( ) , String > {
373+ if self . explicitly_set . is_some ( ) {
374+ return Ok ( ( ) ) ;
375+ }
376+
377+ // `-C link-self-contained=[-+]linker` is only stable on x64 linux.
378+ let check_linker = |components : LinkSelfContainedComponents , polarity : & str | {
379+ let has_linker = components. is_linker_enabled ( ) ;
380+ if has_linker && target_tuple. tuple ( ) != "x86_64-unknown-linux-gnu" {
381+ return Err ( format ! (
382+ "`-C link-self-contained={polarity}linker` is unstable on the `{target_tuple}` \
383+ target. The `-Z unstable-options` flag must also be passed to use it on this target",
384+ ) ) ;
385+ }
386+ Ok ( ( ) )
387+ } ;
388+ check_linker ( self . enabled_components , "+" ) ?;
389+ check_linker ( self . disabled_components , "-" ) ?;
390+
391+ // Since only the linker component is stable, any other component used is unstable, and
392+ // that's an error.
393+ let unstable_enabled = self . enabled_components - LinkSelfContainedComponents :: LINKER ;
394+ let unstable_disabled = self . disabled_components - LinkSelfContainedComponents :: LINKER ;
395+ if !unstable_enabled. union ( unstable_disabled) . is_empty ( ) {
396+ return Err ( String :: from (
397+ "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off`/`-linker`\
398+ /`+linker` are stable, the `-Z unstable-options` flag must also be passed to use \
399+ the unstable values",
400+ ) ) ;
401+ }
402+
403+ Ok ( ( ) )
376404 }
377405
378406 /// Returns whether the self-contained linker component was enabled on the CLI, using the
@@ -399,7 +427,7 @@ impl LinkSelfContained {
399427 }
400428}
401429
402- /// The different values that `-Z linker-features` can take on the CLI: a list of individually
430+ /// The different values that `-C linker-features` can take on the CLI: a list of individually
403431/// enabled or disabled features used during linking.
404432///
405433/// There is no need to enable or disable them in bulk. Each feature is fine-grained, and can be
@@ -439,6 +467,44 @@ impl LinkerFeaturesCli {
439467 _ => None ,
440468 }
441469 }
470+
471+ /// When *not* using `-Z unstable-options` on the CLI, ensure only stable linker features are
472+ /// used, for the given `TargetTuple`. Returns `Ok` if no unstable variants are used.
473+ /// The caller should ensure that e.g. `nightly_options::is_unstable_enabled()`
474+ /// returns false.
475+ pub ( crate ) fn check_unstable_variants ( & self , target_tuple : & TargetTuple ) -> Result < ( ) , String > {
476+ // `-C linker-features=[-+]lld` is only stable on x64 linux.
477+ let check_lld = |features : LinkerFeatures , polarity : & str | {
478+ let has_lld = features. is_lld_enabled ( ) ;
479+ if has_lld && target_tuple. tuple ( ) != "x86_64-unknown-linux-gnu" {
480+ return Err ( format ! (
481+ "`-C linker-features={polarity}lld` is unstable on the `{target_tuple}` \
482+ target. The `-Z unstable-options` flag must also be passed to use it on this target",
483+ ) ) ;
484+ }
485+ Ok ( ( ) )
486+ } ;
487+ check_lld ( self . enabled , "+" ) ?;
488+ check_lld ( self . disabled , "-" ) ?;
489+
490+ // Since only lld is stable, any non-lld feature used is unstable, and that's an error.
491+ let unstable_enabled = self . enabled - LinkerFeatures :: LLD ;
492+ let unstable_disabled = self . disabled - LinkerFeatures :: LLD ;
493+ if !unstable_enabled. union ( unstable_disabled) . is_empty ( ) {
494+ let unstable_features: Vec < _ > = unstable_enabled
495+ . iter ( )
496+ . map ( |f| format ! ( "+{}" , f. as_str( ) . unwrap( ) ) )
497+ . chain ( unstable_disabled. iter ( ) . map ( |f| format ! ( "-{}" , f. as_str( ) . unwrap( ) ) ) )
498+ . collect ( ) ;
499+ return Err ( format ! (
500+ "the requested `-C linker-features={}` are unstable, and also require the \
501+ `-Z unstable-options` flag to be usable",
502+ unstable_features. join( "," ) ,
503+ ) ) ;
504+ }
505+
506+ Ok ( ( ) )
507+ }
442508}
443509
444510/// Used with `-Z assert-incr-state`.
@@ -2595,26 +2661,21 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
25952661 }
25962662 }
25972663
2598- if !nightly_options:: is_unstable_enabled ( matches)
2599- && cg. force_frame_pointers == FramePointer :: NonLeaf
2600- {
2664+ let unstable_options_enabled = nightly_options:: is_unstable_enabled ( matches) ;
2665+ if !unstable_options_enabled && cg. force_frame_pointers == FramePointer :: NonLeaf {
26012666 early_dcx. early_fatal (
26022667 "`-Cforce-frame-pointers=non-leaf` or `always` also requires `-Zunstable-options` \
26032668 and a nightly compiler",
26042669 )
26052670 }
26062671
2607- // For testing purposes, until we have more feedback about these options: ensure `-Z
2608- // unstable-options` is required when using the unstable `-C link-self-contained` and `-C
2609- // linker-flavor` options.
2610- if !nightly_options:: is_unstable_enabled ( matches) {
2611- let uses_unstable_self_contained_option =
2612- cg. link_self_contained . are_unstable_variants_set ( ) ;
2613- if uses_unstable_self_contained_option {
2614- early_dcx. early_fatal (
2615- "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \
2616- the `-Z unstable-options` flag must also be passed to use the unstable values",
2617- ) ;
2672+ let target_triple = parse_target_triple ( early_dcx, matches) ;
2673+
2674+ // Ensure `-Z unstable-options` is required when using the unstable `-C link-self-contained` and
2675+ // `-C linker-flavor` options.
2676+ if !unstable_options_enabled {
2677+ if let Err ( error) = cg. link_self_contained . check_unstable_variants ( & target_triple) {
2678+ early_dcx. early_fatal ( error) ;
26182679 }
26192680
26202681 if let Some ( flavor) = cg. linker_flavor {
@@ -2646,7 +2707,6 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
26462707 let cg = cg;
26472708
26482709 let sysroot_opt = matches. opt_str ( "sysroot" ) . map ( |m| PathBuf :: from ( & m) ) ;
2649- let target_triple = parse_target_triple ( early_dcx, matches) ;
26502710 let opt_level = parse_opt_level ( early_dcx, matches, & cg) ;
26512711 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
26522712 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
@@ -2655,6 +2715,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
26552715 let debuginfo = select_debuginfo ( matches, & cg) ;
26562716 let debuginfo_compression = unstable_opts. debuginfo_compression ;
26572717
2718+ if !unstable_options_enabled {
2719+ if let Err ( error) = cg. linker_features . check_unstable_variants ( & target_triple) {
2720+ early_dcx. early_fatal ( error) ;
2721+ }
2722+ }
2723+
26582724 let crate_name = matches. opt_str ( "crate-name" ) ;
26592725 let unstable_features = UnstableFeatures :: from_environment ( crate_name. as_deref ( ) ) ;
26602726 // Parse any `-l` flags, which link to native libraries.
0 commit comments