add target feature ABI checks for SPARC
Project: rust-lang/rust | Language: Rust | Concepts: api-design, error-handling, testing-strategy | Difficulty: senior
Link: https://github.com/rust-lang/rust/pull/160562
The problem
SPARC targets in the Rust compiler did not have sufficient checks to ensure that the selected ABI (Application Binary Interface) and enabled target features were consistent and valid. This could cause miscompilations or link-time errors, especially since the SPARC V8+ ABI is distinct and not all combinations of features and ABIs are valid or supported.
Why it's non-trivial
A naive fix might only check for a single feature or ABI flag, but the real challenge is that:
- SPARC and SPARC64 have different sets of valid ABIs and features.
- Some fields (like
llvm_abiname,llvm_floatabi, andrustc_abi) are unused or must be unset for certain architectures. - The
v8plusfeature is ABI-significant and must be handled carefully to avoid generating binaries that can't be linked or run. - The compiler must emit helpful diagnostics and future-proof warnings, not just fail silently or with cryptic errors.
The approach
The PR introduces explicit checks and constraints for SPARC and SPARC64 targets, updates enums to represent new ABIs, and adjusts tests and diagnostics. Key changes:
1. Add ABI and feature checks for SPARC and SPARC64
+ Arch::Sparc => {
+ check!(
+ self.llvm_abiname == LlvmAbi::Unspecified,
+ "`llvm_abiname` is unused on SPARC"
+ );
+ check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on SPARC");
+ check_matches!(
+ (&self.rustc_abi, &self.cfg_abi),
+ (Some(RustcAbi::SparcV8Plus), CfgAbi::V8Plus)
+ | (None, CfgAbi::Unspecified | CfgAbi::Other(_)),
+ "invalid SPARC Rust-specific ABI and `cfg(target_abi)` combination:\n\
+ Rust-specific ABI: {:?}\n\
+ cfg(target_abi): {}",
+ self.rustc_abi,
+ self.cfg_abi,
+ );
+ }
+ Arch::Sparc64 => {
+ check!(
+ self.llvm_abiname == LlvmAbi::Unspecified,
+ "`llvm_abiname` is unused on SPARC-64"
+ );
+ check!(self.llvm_floatabi.is_none(), "`llvm_floatabi` is unused on SPARC-64");
+ check!(self.rustc_abi.is_none(), "`rustc_abi` is unused on SPARC-64");
+ check_matches!(
+ self.cfg_abi,
+ CfgAbi::Unspecified | CfgAbi::Other(_),
+ "invalid `target_abi` for SPARC-64"
+ );
+ }
What it does:
- For SPARC, ensures that only the correct ABI and target features are set, and that unused fields are unset.
- For SPARC64, enforces that only valid ABIs are specified and that SPARC32-specific fields are not set.
2. Extend enums to represent new ABIs
+ /// On SPARC-32: use the V8+ ABI.
+ SparcV8Plus = "sparc-v8plus",
and
+ V8Plus = "v8plus",
What it does:
- Adds
SparcV8PlustoRustcAbiandV8PlustoCfgAbi, so that these ABIs can be represented and checked in the target specification.
3. Update the SPARC target specification
+ rustc_abi: Some(RustcAbi::SparcV8Plus),
...
+ cfg_abi: CfgAbi::V8Plus,
What it does:
- Sets the correct ABI in the SPARC target definition, making the target spec explicit and consistent.
4. Add and constrain target features for SPARC/64
+ (
+ "soft-float",
+ InternalOnly { reason: "unsupported ABI-configuration feature", hard_error: false },
+ &[],
+ ),
and
+ Arch::Sparc => {
+ // We currently don't have a soft-float target for SPARC.
+ // We need to pin down v8plus as it is a separate ABI (indicated in object files so
+ // things cannot be linked across ABI boundaries).
+ match self.rustc_abi {
+ None => FeatureConstraints {
+ required: &[],
+ incompatible: &["soft-float", "v8plus"],
+ },
+ Some(RustcAbi::SparcV8Plus) => {
+ FeatureConstraints { required: &["v8plus"], incompatible: &["soft-float"] }
+ }
+ _ => unreachable!(),
+ }
+ }
+ Arch::Sparc64 => {
+ // We currently don't have a soft-float target for SPARC64.
+ // v8plus is for 32bit SPARC only.
+ FeatureConstraints { required: &[], incompatible: &["soft-float", "v8plus"] }
+ }
What it does:
- Disables unsupported features (like "soft-float") for SPARC.
- Requires "v8plus" for the V8+ ABI, and forbids it otherwise.
- For SPARC64, forbids both "soft-float" and "v8plus".
5. Update tests and diagnostics
+//[sparc_feature_v8plus,sparc_cpu_v9_feature_v8plus]~? WARN `v8plus` must be disabled
and in stderr files:
+warning: target feature `v8plus` must be disabled to ensure that the ABI of the current target can be implemented correctly
+ |
+ = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
What it does:
- Ensures that tests expect the new warnings and errors when invalid feature/ABI combinations are used.
- Communicates to users that previously accepted configurations will become errors in the future.
6. Update the list of known target_abi values
+ = note: expected values for `target_abi` are: ..., `v8plus`, ...
What it does:
- Documents the new valid ABI value for SPARC in diagnostics.
From the review thread
RalfJung: Ah, the
sparc-unknown-linux-gnutarget enables v8plus... that's a bit surprising given that I was told that the ABI isn't actually implemented in LLVM yet?
This is also a tier 3 target without a listed target maintainer, so I feel inclined to just remove the target feature from the target spec.
No notable review discussion on this PR.
Takeaways
- Architectural and ABI constraints must be explicitly encoded and checked in target specifications. Failing to do so can result in subtle miscompilations or link-time errors that are hard to debug.
- Unused or architecture-specific fields should be validated and rejected for targets where they do not apply. This prevents accidental configuration drift and clarifies intent.
- Compiler diagnostics should guide users toward valid configurations and warn about future incompatibilities. Clear, actionable warnings help users migrate and avoid breaking changes.
- Tests must be updated to reflect new invariants and error conditions introduced by stricter validation. This ensures that changes are robust and that regressions are caught early.