Skip to content

Commit c4fb58f

Browse files
committed
target specs: tighten checks for llvm_abiname and llvm_floatabi, and tie them to cfg(target_abi)
1 parent d1ee5e5 commit c4fb58f

2 files changed

Lines changed: 254 additions & 40 deletions

File tree

compiler/rustc_target/src/spec/base/apple/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,12 @@ pub(crate) fn base(
127127
let link_env_remove = link_env_remove(&os);
128128
let unversioned_llvm_target = unversioned_llvm_target(&os, arch, env);
129129
let mut opts = TargetOptions {
130-
llvm_floatabi: Some(FloatAbi::Hard),
130+
llvm_floatabi: if arch.target_arch() == crate::spec::Arch::Arm {
131+
Some(FloatAbi::Hard)
132+
} else {
133+
// `llvm_floatabi` makes no sense on x86 and aarch64.
134+
None
135+
},
131136
os,
132137
env: env.target_env(),
133138
abi: env.target_abi(),

compiler/rustc_target/src/spec/mod.rs

Lines changed: 248 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,7 +1005,7 @@ crate::target_spec_enum! {
10051005
pub enum RustcAbi {
10061006
/// On x86-32 only: make use of SSE and SSE2 for ABI purposes.
10071007
X86Sse2 = "x86-sse2",
1008-
/// On x86-32/64 and S390x: do not use any FPU or SIMD registers for the ABI.
1008+
/// On x86-32/64, aarch64, and S390x: do not use any FPU or SIMD registers for the ABI.
10091009
Softfloat = "softfloat", "x86-softfloat",
10101010
}
10111011

@@ -3183,69 +3183,277 @@ impl Target {
31833183
);
31843184
}
31853185

3186-
// Check that RISC-V targets always specify which ABI they use,
3187-
// and that ARM targets specify their float ABI.
3186+
// Check ABI flag consistency, for the architectures where we have proper ABI treatment.
3187+
// To ensure targets are trated consistently, please consult with the team before allowing
3188+
// new cases.
31883189
match self.arch {
3190+
Arch::X86 => {
3191+
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on x86-32");
3192+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on x86-32");
3193+
check_matches!(
3194+
(&self.rustc_abi, &self.abi),
3195+
// FIXME: we do not currently set a target_abi for softfloat targets here,
3196+
// but we probably should, so we already allow it.
3197+
(Some(RustcAbi::Softfloat), Abi::SoftFloat | Abi::Unspecified | Abi::Other(_))
3198+
| (
3199+
Some(RustcAbi::X86Sse2) | None,
3200+
Abi::Uwp | Abi::Llvm | Abi::Sim | Abi::Unspecified | Abi::Other(_)
3201+
),
3202+
"invalid x86-32 Rust-specific ABI and `cfg(target_abi)` combination:\n\
3203+
Rust-specific ABI: {:?}\n\
3204+
cfg(target_abi): {}",
3205+
self.rustc_abi,
3206+
self.abi,
3207+
);
3208+
}
3209+
Arch::X86_64 => {
3210+
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on x86-64");
3211+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on x86-64");
3212+
// FIXME: we do not currently set a target_abi for softfloat targets here, but we
3213+
// probably should, so we already allow it.
3214+
// FIXME: Ensure that target_abi = "x32" correlates with actually using that ABI.
3215+
// Do any of the others need a similar check?
3216+
check_matches!(
3217+
(&self.rustc_abi, &self.abi),
3218+
(Some(RustcAbi::Softfloat), Abi::SoftFloat | Abi::Unspecified | Abi::Other(_))
3219+
| (
3220+
None,
3221+
Abi::X32
3222+
| Abi::Llvm
3223+
| Abi::Fortanix
3224+
| Abi::Uwp
3225+
| Abi::MacAbi
3226+
| Abi::Sim
3227+
| Abi::Unspecified
3228+
| Abi::Other(_)
3229+
),
3230+
"invalid x86-64 Rust-specific ABI and `cfg(target_abi)` combination:\n\
3231+
Rust-specific ABI: {:?}\n\
3232+
cfg(target_abi): {}",
3233+
self.rustc_abi,
3234+
self.abi,
3235+
);
3236+
}
31893237
Arch::RiscV32 => {
3238+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on RISC-V");
3239+
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on RISC-V");
31903240
check_matches!(
3191-
&*self.llvm_abiname,
3192-
"ilp32" | "ilp32f" | "ilp32d" | "ilp32e",
3193-
"invalid RISC-V ABI name: {}",
3241+
(&*self.llvm_abiname, &self.abi),
3242+
("ilp32", Abi::Unspecified | Abi::Other(_))
3243+
| ("ilp32f", Abi::Unspecified | Abi::Other(_))
3244+
| ("ilp32d", Abi::Unspecified | Abi::Other(_))
3245+
| ("ilp32e", Abi::Ilp32e),
3246+
"invalid RISC-V ABI name and `cfg(target_abi)` combination:\n\
3247+
ABI name: {}\n\
3248+
cfg(target_abi): {}",
31943249
self.llvm_abiname,
3250+
self.abi,
31953251
);
31963252
}
31973253
Arch::RiscV64 => {
31983254
// Note that the `lp64e` is still unstable as it's not (yet) part of the ELF psABI.
3255+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on RISC-V");
3256+
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on RISC-V");
31993257
check_matches!(
3200-
&*self.llvm_abiname,
3201-
"lp64" | "lp64f" | "lp64d" | "lp64e",
3202-
"invalid RISC-V ABI name: {}",
3258+
(&*self.llvm_abiname, &self.abi),
3259+
("lp64", Abi::Unspecified | Abi::Other(_))
3260+
| ("lp64f", Abi::Unspecified | Abi::Other(_))
3261+
| ("lp64d", Abi::Unspecified | Abi::Other(_))
3262+
| ("lp64e", Abi::Unspecified | Abi::Other(_)),
3263+
"invalid RISC-V ABI name and `cfg(target_abi)` combination:\n\
3264+
ABI name: {}\n\
3265+
cfg(target_abi): {}",
32033266
self.llvm_abiname,
3267+
self.abi,
32043268
);
32053269
}
32063270
Arch::Arm => {
3207-
check!(
3208-
self.llvm_floatabi.is_some(),
3209-
"ARM targets must set `llvm-floatabi` to `hard` or `soft`",
3271+
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on ARM");
3272+
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on ARM");
3273+
check_matches!(
3274+
(&self.llvm_floatabi, &self.abi),
3275+
(
3276+
Some(FloatAbi::Hard),
3277+
Abi::EabiHf | Abi::Uwp | Abi::Unspecified | Abi::Other(_)
3278+
) | (Some(FloatAbi::Soft), Abi::Eabi),
3279+
"Invalid combination of float ABI and `cfg(target_abi)` for ARM target\n\
3280+
float ABI: {:?}\n\
3281+
cfg(target_abi): {}",
3282+
self.llvm_floatabi,
3283+
self.abi,
32103284
)
32113285
}
3212-
// PowerPC64 targets that are not AIX must set their ABI to either ELFv1 or ELFv2
3286+
Arch::AArch64 => {
3287+
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on aarch64");
3288+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on aarch64");
3289+
// FIXME: Ensure that target_abi = "ilp32" correlates with actually using that ABI.
3290+
// Do any of the others need a similar check?
3291+
check_matches!(
3292+
(&self.rustc_abi, &self.abi),
3293+
(Some(RustcAbi::Softfloat), Abi::SoftFloat)
3294+
| (
3295+
None,
3296+
Abi::Ilp32
3297+
| Abi::Llvm
3298+
| Abi::MacAbi
3299+
| Abi::Sim
3300+
| Abi::Uwp
3301+
| Abi::Unspecified
3302+
| Abi::Other(_)
3303+
),
3304+
"invalid aarch64 Rust-specific ABI and `cfg(target_abi)` combination:\n\
3305+
Rust-specific ABI: {:?}\n\
3306+
cfg(target_abi): {}",
3307+
self.rustc_abi,
3308+
self.abi,
3309+
);
3310+
}
3311+
Arch::PowerPC => {
3312+
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on PowerPC");
3313+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on PowerPC");
3314+
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on PowerPC");
3315+
// FIXME: Check that `target_abi` matches the actually configured ABI (with or
3316+
// without SPE).
3317+
check_matches!(
3318+
self.abi,
3319+
Abi::Spe | Abi::Unspecified | Abi::Other(_),
3320+
"invalid `target_abi` for PowerPC"
3321+
);
3322+
}
32133323
Arch::PowerPC64 => {
3324+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on PowerPC64");
3325+
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on PowerPC64");
3326+
// PowerPC64 targets that are not AIX must set their ABI to either ELFv1 or ELFv2
32143327
if self.os == Os::Aix {
3215-
check!(
3216-
self.llvm_abiname.is_empty(),
3217-
"AIX targets always use the AIX ABI and `llvm_abiname` should be left empty",
3328+
// FIXME: Check that `target_abi` matches the actually configured ABI
3329+
// (vec-default vs vec-ext).
3330+
check_matches!(
3331+
(&*self.llvm_abiname, &self.abi),
3332+
("", Abi::VecDefault | Abi::VecExtAbi),
3333+
"invalid PowerPC64 AIX ABI name and `cfg(target_abi)` combination:\n\
3334+
ABI name: {}\n\
3335+
cfg(target_abi): {}",
3336+
self.llvm_abiname,
3337+
self.abi,
32183338
);
32193339
} else if self.endian == Endian::Big {
32203340
check_matches!(
3221-
&*self.llvm_abiname,
3222-
"elfv1" | "elfv2",
3223-
"invalid PowerPC64 ABI name: {}",
3341+
(&*self.llvm_abiname, &self.abi),
3342+
("elfv1", Abi::ElfV1) | ("elfv2", Abi::ElfV2),
3343+
"invalid PowerPC64 big-endian ABI name and `cfg(target_abi)` combination:\n\
3344+
ABI name: {}\n\
3345+
cfg(target_abi): {}",
32243346
self.llvm_abiname,
3347+
self.abi,
32253348
);
32263349
} else {
3227-
check!(
3228-
self.llvm_abiname == "elfv2",
3229-
"little-endian PowerPC64 targets only support the `elfv2` ABI",
3350+
check_matches!(
3351+
(&*self.llvm_abiname, &self.abi),
3352+
("elfv2", Abi::ElfV2),
3353+
"invalid PowerPC64 little-endian ABI name and `cfg(target_abi)` combination:\n\
3354+
ABI name: {}\n\
3355+
cfg(target_abi): {}",
3356+
self.llvm_abiname,
3357+
self.abi,
32303358
);
32313359
}
32323360
}
3233-
_ => {}
3234-
}
3235-
3236-
// Check consistency of Rust ABI declaration.
3237-
if let Some(rust_abi) = self.rustc_abi {
3238-
match rust_abi {
3239-
RustcAbi::X86Sse2 => check_matches!(
3240-
self.arch,
3241-
Arch::X86,
3242-
"`x86-sse2` ABI is only valid for x86-32 targets"
3243-
),
3244-
RustcAbi::Softfloat => check_matches!(
3245-
self.arch,
3246-
Arch::X86 | Arch::X86_64 | Arch::S390x | Arch::AArch64,
3247-
"`softfloat` ABI is only valid for x86, s390x, and aarch64 targets"
3248-
),
3361+
Arch::S390x => {
3362+
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on s390x");
3363+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on s390x");
3364+
check_matches!(
3365+
(&self.rustc_abi, &self.abi),
3366+
(Some(RustcAbi::Softfloat), Abi::SoftFloat)
3367+
| (None, Abi::Unspecified | Abi::Other(_)),
3368+
"invalid s390x Rust-specific ABI and `cfg(target_abi)` combination:\n\
3369+
Rust-specific ABI: {:?}\n\
3370+
cfg(target_abi): {}",
3371+
self.rustc_abi,
3372+
self.abi,
3373+
);
3374+
}
3375+
Arch::LoongArch32 => {
3376+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on LoongArch");
3377+
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on LoongArch");
3378+
check_matches!(
3379+
(&*self.llvm_abiname, &self.abi),
3380+
("ilp32s", Abi::SoftFloat)
3381+
| ("ilp32f", Abi::Unspecified | Abi::Other(_))
3382+
| ("ilp32d", Abi::Unspecified | Abi::Other(_)),
3383+
"invalid LoongArch ABI name and `cfg(target_abi)` combination:\n\
3384+
ABI name: {}\n\
3385+
cfg(target_abi): {}",
3386+
self.llvm_abiname,
3387+
self.abi,
3388+
);
3389+
}
3390+
Arch::LoongArch64 => {
3391+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on LoongArch");
3392+
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on LoongArch");
3393+
check_matches!(
3394+
(&*self.llvm_abiname, &self.abi),
3395+
("lp64s", Abi::SoftFloat)
3396+
| ("lp64f", Abi::Unspecified | Abi::Other(_))
3397+
| ("lp64d", Abi::Unspecified | Abi::Other(_)),
3398+
"invalid LoongArch ABI name and `cfg(target_abi)` combination:\n\
3399+
ABI name: {}\n\
3400+
cfg(target_abi): {}",
3401+
self.llvm_abiname,
3402+
self.abi,
3403+
);
3404+
}
3405+
Arch::Mips => {
3406+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on MIPS");
3407+
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on MIPS");
3408+
check_matches!(
3409+
(&*self.llvm_abiname, &self.abi),
3410+
// FIXME: we should force it to always be non-empty.
3411+
("o32", Abi::Unspecified | Abi::Other(_))
3412+
| ("", Abi::Unspecified | Abi::Other(_)),
3413+
"invalid MIPS ABI name and `cfg(target_abi)` combination:\n\
3414+
ABI name: {}\n\
3415+
cfg(target_abi): {}",
3416+
self.llvm_abiname,
3417+
self.abi,
3418+
);
3419+
}
3420+
Arch::Mips64 | Arch::Mips64r6 => {
3421+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on MIPS");
3422+
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on MIPS");
3423+
check_matches!(
3424+
(&*self.llvm_abiname, &self.abi),
3425+
("n64", Abi::Abi64),
3426+
"invalid MIPS ABI name and `cfg(target_abi)` combination:\n\
3427+
ABI name: {}\n\
3428+
cfg(target_abi): {}",
3429+
self.llvm_abiname,
3430+
self.abi,
3431+
);
3432+
}
3433+
Arch::CSky => {
3434+
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on CSky");
3435+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on CSky");
3436+
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on CSky");
3437+
// FIXME: Check that `target_abi` matches the actually configured ABI (v2 vs v2hf).
3438+
check_matches!(
3439+
self.abi,
3440+
Abi::AbiV2 | Abi::AbiV2Hf,
3441+
"invalid `target_abi` for CSky"
3442+
);
3443+
}
3444+
ref arch => {
3445+
check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on {arch}");
3446+
// Ensure consistency among built-in targets, but give JSON targets the opportunity
3447+
// to experiment with these.
3448+
if kind == TargetKind::Builtin {
3449+
check!(self.llvm_abiname.is_empty(), "`llvm_abiname` is unused on {arch}");
3450+
check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on {arch}");
3451+
check_matches!(
3452+
self.abi,
3453+
Abi::Unspecified | Abi::Other(_),
3454+
"`target_abi` is unused on {arch}"
3455+
);
3456+
}
32493457
}
32503458
}
32513459

@@ -3305,7 +3513,8 @@ impl Target {
33053513
let recycled_target =
33063514
Target::from_json(&serde_json::to_string(&self.to_json()).unwrap()).map(|(j, _)| j);
33073515
self.update_to_cli();
3308-
self.check_consistency(TargetKind::Builtin).unwrap();
3516+
self.check_consistency(TargetKind::Builtin)
3517+
.unwrap_or_else(|err| panic!("Target consistency check failed:\n{err}"));
33093518
assert_eq!(recycled_target, Ok(self));
33103519
}
33113520

0 commit comments

Comments
 (0)