Rollup merge of #152973 - RalfJung:soft-float, r=JonathanBrouwer

remove -Csoft-float

This fixes https://github.com/rust-lang/rust/issues/129893 by removing the offending flag.

The flag has been added in pre-1.0 times (https://github.com/rust-lang/rust/pull/9617) without much discussion, probably with the intent to mirror `-msoft-float` in C compilers. It never properly mirrored clang though because it only affected the LLVM float ABI setting, not the "soft-float" target feature (the clang flag sets both). It is also blatantly unsound because it affects how float arguments are passed, making it UB to invoke parts of the standard library.

The flag got deprecated with Rust 1.83 (released November 2024), and in the year since then, nobody spoke up in rust-lang/rust#129893 to have it preserved. I think it is time to remove it. I can totally imagine us bringing back a similar flag, properly registered as a target modifier to preserve soundness, but that should come with a coherent design that works for more than one architecture (the flag only does anything on ARM).

Blocked on approval of https://github.com/rust-lang/compiler-team/issues/971.
Fixes https://github.com/rust-lang/rust/issues/154106
This commit is contained in:
Stuart Cook
2026-03-20 15:33:06 +11:00
committed by GitHub
6 changed files with 38 additions and 50 deletions
+2 -10
View File
@@ -23,9 +23,7 @@
use rustc_session::Session;
use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
use rustc_span::{BytePos, InnerSpan, Pos, RemapPathScopeComponents, SpanData, SyntaxContext, sym};
use rustc_target::spec::{
Arch, CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel,
};
use rustc_target::spec::{CodeModel, FloatAbi, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel};
use tracing::{debug, trace};
use crate::back::lto::{Buffer, ModuleBuffer};
@@ -206,13 +204,7 @@ pub(crate) fn target_machine_factory(
let reloc_model = to_llvm_relocation_model(sess.relocation_model());
let (opt_level, _) = to_llvm_opt_settings(optlvl);
let float_abi = if sess.target.arch == Arch::Arm && sess.opts.cg.soft_float {
llvm::FloatAbi::Soft
} else {
// `validate_commandline_args_with_session_available` has already warned about this being
// ignored. Let's make sure LLVM doesn't suddenly start using this flag on more targets.
to_llvm_float_abi(sess.target.llvm_floatabi)
};
let float_abi = to_llvm_float_abi(sess.target.llvm_floatabi);
let ffunction_sections =
sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections);
-1
View File
@@ -637,7 +637,6 @@ macro_rules! tracked {
tracked!(profile_use, Some(PathBuf::from("abc")));
tracked!(relocation_model, Some(RelocModel::Pic));
tracked!(relro_level, Some(RelroLevel::Full));
tracked!(soft_float, true);
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
tracked!(target_cpu, Some(String::from("abc")));
-11
View File
@@ -517,17 +517,6 @@ pub(crate) struct FailedToCreateProfiler {
pub(crate) err: String,
}
#[derive(Diagnostic)]
#[diag("`-Csoft-float` is ignored on this target; it only has an effect on *eabihf targets")]
#[note("this may become a hard error in a future version of Rust")]
pub(crate) struct SoftFloatIgnored;
#[derive(Diagnostic)]
#[diag("`-Csoft-float` is unsound and deprecated; use a corresponding *eabi target instead")]
#[note("it will be removed or ignored in a future version of Rust")]
#[note("see issue #129893 <https://github.com/rust-lang/rust/issues/129893> for more information")]
pub(crate) struct SoftFloatDeprecated;
#[derive(Diagnostic)]
#[diag("unexpected `--cfg {$cfg}` flag")]
#[note("config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}`")]
+2
View File
@@ -1,5 +1,7 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![feature(const_option_ops)]
#![feature(const_trait_impl)]
#![feature(default_field_values)]
#![feature(iter_intersperse)]
#![feature(macro_derive)]
+34 -18
View File
@@ -611,7 +611,7 @@ macro_rules! options {
$parse:ident,
[$dep_tracking_marker:ident $( $tmod:ident )?],
$desc:expr
$(, is_deprecated_and_do_nothing: $dnn:literal )?)
$(, removed: $removed:ident )?)
),* ,) =>
(
#[derive(Clone)]
@@ -667,7 +667,7 @@ pub fn gather_target_modifiers(
pub const $stat: OptionDescrs<$struct_name> =
&[ $( OptionDesc{ name: stringify!($opt), setter: $optmod::$opt,
type_desc: desc::$parse, desc: $desc, is_deprecated_and_do_nothing: false $( || $dnn )?,
type_desc: desc::$parse, desc: $desc, removed: None $( .or(Some(RemovedOption::$removed)) )?,
tmod: tmod_enum_opt!($struct_name, $tmod_enum_name, $opt, $($tmod),*) } ),* ];
mod $optmod {
@@ -705,6 +705,12 @@ macro_rules! redirect_field {
type OptionSetter<O> = fn(&mut O, v: Option<&str>) -> bool;
type OptionDescrs<O> = &'static [OptionDesc<O>];
/// Indicates whether a removed option should warn or error.
enum RemovedOption {
Warn,
Err,
}
pub struct OptionDesc<O> {
name: &'static str,
setter: OptionSetter<O>,
@@ -712,7 +718,7 @@ pub struct OptionDesc<O> {
type_desc: &'static str,
// description for option from options table
desc: &'static str,
is_deprecated_and_do_nothing: bool,
removed: Option<RemovedOption>,
tmod: Option<OptionsTargetModifiers>,
}
@@ -743,18 +749,18 @@ fn build_options<O: Default>(
let option_to_lookup = key.replace('-', "_");
match descrs.iter().find(|opt_desc| opt_desc.name == option_to_lookup) {
Some(OptionDesc {
name: _,
setter,
type_desc,
desc,
is_deprecated_and_do_nothing,
tmod,
}) => {
if *is_deprecated_and_do_nothing {
Some(OptionDesc { name: _, setter, type_desc, desc, removed, tmod }) => {
if let Some(removed) = removed {
// deprecation works for prefixed options only
assert!(!prefix.is_empty());
early_dcx.early_warn(format!("`-{prefix} {key}`: {desc}"));
match removed {
RemovedOption::Warn => {
early_dcx.early_warn(format!("`-{prefix} {key}`: {desc}"))
}
RemovedOption::Err => {
early_dcx.early_fatal(format!("`-{prefix} {key}`: {desc}"))
}
}
}
if !setter(&mut op, value) {
match value {
@@ -783,6 +789,7 @@ fn build_options<O: Default>(
#[allow(non_upper_case_globals)]
mod desc {
pub(crate) const parse_ignore: &str = "<ignored>"; // should not be user-visible
pub(crate) const parse_no_value: &str = "no value";
pub(crate) const parse_bool: &str =
"one of: `y`, `yes`, `on`, `true`, `n`, `no`, `off` or `false`";
@@ -889,6 +896,12 @@ pub mod parse {
pub(crate) use super::*;
pub(crate) const MAX_THREADS_CAP: usize = 256;
/// Ignore the value. Used for removed options where we don't actually want to store
/// anything in the session.
pub(crate) fn parse_ignore(_slot: &mut (), _v: Option<&str>) -> bool {
true
}
/// This is for boolean options that don't take a value, and are true simply
/// by existing on the command-line.
///
@@ -2059,7 +2072,7 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
#[rustc_lint_opt_deny_field_access("documented to do nothing")]
ar: String = (String::new(), parse_string, [UNTRACKED],
"this option is deprecated and does nothing",
is_deprecated_and_do_nothing: true),
removed: Warn),
#[rustc_lint_opt_deny_field_access("use `Session::code_model` instead of this field")]
code_model: Option<CodeModel> = (None, parse_code_model, [TRACKED],
"choose the code model to use (`rustc --print code-models` for details)"),
@@ -2098,7 +2111,7 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
inline_threshold: Option<u32> = (None, parse_opt_number, [UNTRACKED],
"this option is deprecated and does nothing \
(consider using `-Cllvm-args=--inline-threshold=...`)",
is_deprecated_and_do_nothing: true),
removed: Warn),
#[rustc_lint_opt_deny_field_access("use `Session::instrument_coverage` instead of this field")]
instrument_coverage: InstrumentCoverage = (InstrumentCoverage::No, parse_instrument_coverage, [TRACKED],
"instrument the generated code to support LLVM source-based code coverage reports \
@@ -2139,7 +2152,7 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
#[rustc_lint_opt_deny_field_access("documented to do nothing")]
no_stack_check: bool = (false, parse_no_value, [UNTRACKED],
"this option is deprecated and does nothing",
is_deprecated_and_do_nothing: true),
removed: Warn),
no_vectorize_loops: bool = (false, parse_no_value, [TRACKED],
"disable loop vectorization optimization passes"),
no_vectorize_slp: bool = (false, parse_no_value, [TRACKED],
@@ -2173,8 +2186,11 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
"set rpath values in libs/exes (default: no)"),
save_temps: bool = (false, parse_bool, [UNTRACKED],
"save all temporary output files during compilation (default: no)"),
soft_float: bool = (false, parse_bool, [TRACKED],
"deprecated option: use soft float ABI (*eabihf targets only) (default: no)"),
#[rustc_lint_opt_deny_field_access("documented to do nothing")]
soft_float: () = ((), parse_ignore, [UNTRACKED],
"this option has been removed \
(use a corresponding *eabi target instead)",
removed: Err),
#[rustc_lint_opt_deny_field_access("use `Session::split_debuginfo` instead of this field")]
split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED],
"how to handle split-debuginfo, a platform-specific option"),
-10
View File
@@ -1360,16 +1360,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
}
}
}
if sess.opts.cg.soft_float {
if sess.target.arch == Arch::Arm {
sess.dcx().emit_warn(errors::SoftFloatDeprecated);
} else {
// All `use_softfp` does is the equivalent of `-mfloat-abi` in GCC/clang, which only exists on ARM targets.
// We document this flag to only affect `*eabihf` targets, so let's show a warning for all other targets.
sess.dcx().emit_warn(errors::SoftFloatIgnored);
}
}
}
/// Holds data on the current incremental compilation session, if there is one.