Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Target modifiers fix for bool flags without value #138483

Merged
merged 1 commit into from
Mar 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions compiler/rustc_metadata/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,23 @@ metadata_incompatible_rustc =

metadata_incompatible_target_modifiers =
mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}`
.note = `{$flag_name_prefixed}={$flag_local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$flag_extern_value}` in dependency `{$extern_crate}`
.note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with `{$flag_name_prefixed}={$extern_value}` in dependency `{$extern_crate}`
.help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely

metadata_incompatible_target_modifiers_help_allow = if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch={$flag_name}` to silence this error
metadata_incompatible_target_modifiers_help_fix = set `{$flag_name_prefixed}={$flag_extern_value}` in this crate or `{$flag_name_prefixed}={$flag_local_value}` in `{$extern_crate}`
metadata_incompatible_target_modifiers_help_fix = set `{$flag_name_prefixed}={$extern_value}` in this crate or `{$flag_name_prefixed}={$local_value}` in `{$extern_crate}`

metadata_incompatible_target_modifiers_help_fix_l_missed = set `{$flag_name_prefixed}={$extern_value}` in this crate or unset `{$flag_name_prefixed}` in `{$extern_crate}`

metadata_incompatible_target_modifiers_help_fix_r_missed = unset `{$flag_name_prefixed}` in this crate or set `{$flag_name_prefixed}={$local_value}` in `{$extern_crate}`

metadata_incompatible_target_modifiers_l_missed =
mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}`
.note = unset `{$flag_name_prefixed}` in this crate is incompatible with `{$flag_name_prefixed}={$extern_value}` in dependency `{$extern_crate}`
.help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
metadata_incompatible_target_modifiers_r_missed =
mixing `{$flag_name_prefixed}` will cause an ABI mismatch in crate `{$local_crate}`
.note = `{$flag_name_prefixed}={$local_value}` in this crate is incompatible with unset `{$flag_name_prefixed}` in dependency `{$extern_crate}`
.help = the `{$flag_name_prefixed}` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
metadata_incompatible_wasm_link =
`wasm_import_module` is incompatible with other arguments in `#[link]` attributes

Expand Down
69 changes: 51 additions & 18 deletions compiler/rustc_metadata/src/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,57 +358,90 @@ impl CStore {
) {
let span = krate.spans.inner_span.shrink_to_lo();
let allowed_flag_mismatches = &tcx.sess.opts.cg.unsafe_allow_abi_mismatch;
let name = tcx.crate_name(LOCAL_CRATE);
let local_crate = tcx.crate_name(LOCAL_CRATE);
let tmod_extender = |tmod: &TargetModifier| (tmod.extend(), tmod.clone());
let report_diff = |prefix: &String,
opt_name: &String,
flag_local_value: &String,
flag_extern_value: &String| {
flag_local_value: Option<&String>,
flag_extern_value: Option<&String>| {
if allowed_flag_mismatches.contains(&opt_name) {
return;
}
tcx.dcx().emit_err(errors::IncompatibleTargetModifiers {
span,
extern_crate: data.name(),
local_crate: name,
flag_name: opt_name.clone(),
flag_name_prefixed: format!("-{}{}", prefix, opt_name),
flag_local_value: flag_local_value.to_string(),
flag_extern_value: flag_extern_value.to_string(),
});
let extern_crate = data.name();
let flag_name = opt_name.clone();
let flag_name_prefixed = format!("-{}{}", prefix, opt_name);

match (flag_local_value, flag_extern_value) {
(Some(local_value), Some(extern_value)) => {
tcx.dcx().emit_err(errors::IncompatibleTargetModifiers {
span,
extern_crate,
local_crate,
flag_name,
flag_name_prefixed,
local_value: local_value.to_string(),
extern_value: extern_value.to_string(),
})
}
(None, Some(extern_value)) => {
tcx.dcx().emit_err(errors::IncompatibleTargetModifiersLMissed {
span,
extern_crate,
local_crate,
flag_name,
flag_name_prefixed,
extern_value: extern_value.to_string(),
})
}
(Some(local_value), None) => {
tcx.dcx().emit_err(errors::IncompatibleTargetModifiersRMissed {
span,
extern_crate,
local_crate,
flag_name,
flag_name_prefixed,
local_value: local_value.to_string(),
})
}
(None, None) => panic!("Incorrect target modifiers report_diff(None, None)"),
};
};
let mut it1 = mods.iter().map(tmod_extender);
let mut it2 = dep_mods.iter().map(tmod_extender);
let mut left_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
let mut right_name_val: Option<(ExtendedTargetModifierInfo, TargetModifier)> = None;
let no_val = "*".to_string();
loop {
left_name_val = left_name_val.or_else(|| it1.next());
right_name_val = right_name_val.or_else(|| it2.next());
match (&left_name_val, &right_name_val) {
(Some(l), Some(r)) => match l.1.opt.cmp(&r.1.opt) {
cmp::Ordering::Equal => {
if l.0.tech_value != r.0.tech_value {
report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &r.1.value_name);
report_diff(
&l.0.prefix,
&l.0.name,
Some(&l.1.value_name),
Some(&r.1.value_name),
);
}
left_name_val = None;
right_name_val = None;
}
cmp::Ordering::Greater => {
report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name);
report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
right_name_val = None;
}
cmp::Ordering::Less => {
report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val);
report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
left_name_val = None;
}
},
(Some(l), None) => {
report_diff(&l.0.prefix, &l.0.name, &l.1.value_name, &no_val);
report_diff(&l.0.prefix, &l.0.name, Some(&l.1.value_name), None);
left_name_val = None;
}
(None, Some(r)) => {
report_diff(&r.0.prefix, &r.0.name, &no_val, &r.1.value_name);
report_diff(&r.0.prefix, &r.0.name, None, Some(&r.1.value_name));
right_name_val = None;
}
(None, None) => break,
Expand Down
36 changes: 34 additions & 2 deletions compiler/rustc_metadata/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -759,8 +759,40 @@ pub struct IncompatibleTargetModifiers {
pub local_crate: Symbol,
pub flag_name: String,
pub flag_name_prefixed: String,
pub flag_local_value: String,
pub flag_extern_value: String,
pub local_value: String,
pub extern_value: String,
}

#[derive(Diagnostic)]
#[diag(metadata_incompatible_target_modifiers_l_missed)]
#[help]
#[note]
#[help(metadata_incompatible_target_modifiers_help_fix_l_missed)]
#[help(metadata_incompatible_target_modifiers_help_allow)]
pub struct IncompatibleTargetModifiersLMissed {
#[primary_span]
pub span: Span,
pub extern_crate: Symbol,
pub local_crate: Symbol,
pub flag_name: String,
pub flag_name_prefixed: String,
pub extern_value: String,
}

#[derive(Diagnostic)]
#[diag(metadata_incompatible_target_modifiers_r_missed)]
#[help]
#[note]
#[help(metadata_incompatible_target_modifiers_help_fix_r_missed)]
#[help(metadata_incompatible_target_modifiers_help_allow)]
pub struct IncompatibleTargetModifiersRMissed {
#[primary_span]
pub span: Span,
pub extern_crate: Symbol,
pub local_crate: Symbol,
pub flag_name: String,
pub flag_name_prefixed: String,
pub local_value: String,
}

#[derive(Diagnostic)]
Expand Down
52 changes: 28 additions & 24 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,45 +94,49 @@ fn tmod_push_impl(
tmod_vals: &BTreeMap<OptionsTargetModifiers, String>,
tmods: &mut Vec<TargetModifier>,
) {
tmods.push(TargetModifier { opt, value_name: tmod_vals.get(&opt).cloned().unwrap_or_default() })
if let Some(v) = tmod_vals.get(&opt) {
tmods.push(TargetModifier { opt, value_name: v.clone() })
}
}

macro_rules! tmod_push {
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $mods:expr, $tmod_vals:expr) => {
tmod_push_impl(
OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name),
$tmod_vals,
$mods,
);
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr) => {
if *$opt_expr != $init {
tmod_push_impl(
OptionsTargetModifiers::$struct_name($tmod_enum_name::$opt_name),
$tmod_vals,
$mods,
);
}
};
}

macro_rules! gather_tmods {
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
[SUBSTRUCT], [TARGET_MODIFIER]) => {
compile_error!("SUBSTRUCT can't be target modifier");
};
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
[UNTRACKED], [TARGET_MODIFIER]) => {
tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals)
};
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
[TRACKED], [TARGET_MODIFIER]) => {
tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals)
};
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
[TRACKED_NO_CRATE_HASH], [TARGET_MODIFIER]) => {
tmod_push!($struct_name, $tmod_enum_name, $opt_name, $mods, $tmod_vals)
tmod_push!($struct_name, $tmod_enum_name, $opt_name, $opt_expr, $init, $mods, $tmod_vals)
};
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
[SUBSTRUCT], []) => {
$opt_expr.gather_target_modifiers($mods, $tmod_vals);
};
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
[UNTRACKED], []) => {{}};
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
[TRACKED], []) => {{}};
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $mods:expr, $tmod_vals:expr,
($struct_name:ident, $tmod_enum_name:ident, $opt_name:ident, $opt_expr:expr, $init:expr, $mods:expr, $tmod_vals:expr,
[TRACKED_NO_CRATE_HASH], []) => {{}};
}

Expand Down Expand Up @@ -474,7 +478,8 @@ macro_rules! tmod_enum {
$($pout)*
Self::$opt => {
let mut parsed : $t = Default::default();
parse::$parse(&mut parsed, Some($puser_value));
let val = if $puser_value.is_empty() { None } else { Some($puser_value) };
parse::$parse(&mut parsed, val);
ExtendedTargetModifierInfo {
prefix: $prefix.to_string(),
name: stringify!($opt).to_string().replace('_', "-"),
Expand Down Expand Up @@ -569,7 +574,7 @@ macro_rules! options {
_tmod_vals: &BTreeMap<OptionsTargetModifiers, String>,
) {
$({
gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, _mods, _tmod_vals,
gather_tmods!($struct_name, $tmod_enum_name, $opt, &self.$opt, $init, _mods, _tmod_vals,
[$dep_tracking_marker], [$($tmod),*]);
})*
}
Expand Down Expand Up @@ -681,10 +686,9 @@ fn build_options<O: Default>(
),
}
}
if let Some(tmod) = *tmod
&& let Some(value) = value
{
target_modifiers.insert(tmod, value.to_string());
if let Some(tmod) = *tmod {
let v = value.map_or(String::new(), ToOwned::to_owned);
target_modifiers.insert(tmod, v);
}
}
None => early_dcx.early_fatal(format!("unknown {outputname} option: `{key}`")),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//@ no-prefer-dynamic
//@ compile-flags: --target i686-unknown-linux-gnu -Zreg-struct-return=true
//@ needs-llvm-components: x86

#![feature(no_core)]
#![crate_type = "rlib"]
#![no_core]
4 changes: 2 additions & 2 deletions tests/ui/target_modifiers/defaults_check.error.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ LL | #![feature(no_core)]
| ^
|
= help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
= note: `-Zreg-struct-return=true` in this crate is incompatible with `-Zreg-struct-return=` in dependency `default_reg_struct_return`
= help: set `-Zreg-struct-return=` in this crate or `-Zreg-struct-return=true` in `default_reg_struct_return`
= note: `-Zreg-struct-return=true` in this crate is incompatible with unset `-Zreg-struct-return` in dependency `default_reg_struct_return`
= help: unset `-Zreg-struct-return` in this crate or set `-Zreg-struct-return=true` in `default_reg_struct_return`
= help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error

error: aborting due to 1 previous error
Expand Down
13 changes: 13 additions & 0 deletions tests/ui/target_modifiers/no_value_bool.error.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool`
--> $DIR/no_value_bool.rs:16:1
|
LL | #![feature(no_core)]
| ^
|
= help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
= note: unset `-Zreg-struct-return` in this crate is incompatible with `-Zreg-struct-return=true` in dependency `enabled_reg_struct_return`
= help: set `-Zreg-struct-return=true` in this crate or unset `-Zreg-struct-return` in `enabled_reg_struct_return`
= help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error

error: aborting due to 1 previous error

13 changes: 13 additions & 0 deletions tests/ui/target_modifiers/no_value_bool.error_explicit.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool`
--> $DIR/no_value_bool.rs:16:1
|
LL | #![feature(no_core)]
| ^
|
= help: the `-Zreg-struct-return` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely
= note: unset `-Zreg-struct-return` in this crate is incompatible with `-Zreg-struct-return=true` in dependency `enabled_reg_struct_return`
= help: set `-Zreg-struct-return=true` in this crate or unset `-Zreg-struct-return` in `enabled_reg_struct_return`
= help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=reg-struct-return` to silence this error

error: aborting due to 1 previous error

22 changes: 22 additions & 0 deletions tests/ui/target_modifiers/no_value_bool.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Tests that bool target modifier value (true) in dependency crate is ok linked
// with the -Zflag specified without value (-Zflag=true is consistent with -Zflag)

//@ aux-build:enabled_reg_struct_return.rs
//@ compile-flags: --target i686-unknown-linux-gnu -Cpanic=abort
//@ needs-llvm-components: x86

//@ revisions: ok ok_explicit error error_explicit
//@[ok] compile-flags: -Zreg-struct-return
//@[ok_explicit] compile-flags: -Zreg-struct-return=true
//@[error] compile-flags:
//@[error_explicit] compile-flags: -Zreg-struct-return=false
//@[ok] check-pass
//@[ok_explicit] check-pass

#![feature(no_core)]
//[error]~^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool`
//[error_explicit]~^^ ERROR mixing `-Zreg-struct-return` will cause an ABI mismatch in crate `no_value_bool`
#![crate_type = "rlib"]
#![no_core]

extern crate enabled_reg_struct_return;
Loading