Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
17305da
Fix error spans for asm!() args that are macros
gurry Feb 5, 2026
0061a22
rustc_parse_format: improve diagnostics for unsupported debug `=` syntax
Unique-Usman Jan 14, 2026
343b469
Update to Xcode 26.2
madsmtm Feb 2, 2026
85ca098
rustc_parse: improve the error diagnostic for "missing let"
Unique-Usman Feb 1, 2026
5862618
Remove the compiler adhoc group
Kobzol Feb 8, 2026
81fb703
Fix copy-paste bug: use sub_trace.cause instead of sup_trace.cause in…
cuiweixie Feb 8, 2026
2b1dc31
add a new s390x-unknown-none-softfloat target
fneddy Jan 14, 2026
51affa0
add tests for s390x-unknown-none-softfloat
fneddy Jan 22, 2026
7c3d096
allow for variant aliases in target_spec_enum!
fneddy Feb 6, 2026
83dba5b
renamed RustcAbi::X86Softfloat to Softfloat an made an alias to the o…
fneddy Jan 22, 2026
9709215
Rollup merge of #151960 - Unique-Usman:ua/missingletleft, r=estebank
JonathanBrouwer Feb 9, 2026
e0c8737
Rollup merge of #152157 - gurry:131292-asm-concat-unicode, r=petroche…
JonathanBrouwer Feb 9, 2026
3199309
Rollup merge of #152317 - cuiweixie:sup_trace, r=jackh726
JonathanBrouwer Feb 9, 2026
af70d82
Rollup merge of #150897 - Unique-Usman:ua/debug, r=estebank
JonathanBrouwer Feb 9, 2026
1f59a4a
Rollup merge of #151154 - fneddy:s390x_softfloat_abi, r=workingjubilee
JonathanBrouwer Feb 9, 2026
bcd01e7
Rollup merge of #152013 - madsmtm:update-xcode, r=shepmaster
JonathanBrouwer Feb 9, 2026
415780b
Rollup merge of #152326 - Kobzol:remove-compiler-adhoc-group, r=wesle…
JonathanBrouwer Feb 9, 2026
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
33 changes: 17 additions & 16 deletions compiler/rustc_builtin_macros/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,18 @@ fn expand_preparsed_asm(
let msg = "asm template must be a string literal";
let template_sp = template_expr.span;
let template_is_mac_call = matches!(template_expr.kind, ast::ExprKind::MacCall(_));

// Gets the span inside `template_sp` corresponding to the given range
let span_in_template = |range: std::ops::Range<usize>| -> Span {
if template_is_mac_call {
// When the template is a macro call we can't reliably get inner spans
// so just use the entire template span (see ICEs #129503, #131292)
template_sp
} else {
template_sp.from_inner(InnerSpan::new(range.start, range.end))
}
};

let ExprToSpannedString {
symbol: template_str,
style: template_style,
Expand Down Expand Up @@ -382,13 +394,8 @@ fn expand_preparsed_asm(

if !parser.errors.is_empty() {
let err = parser.errors.remove(0);
let err_sp = if template_is_mac_call {
// If the template is a macro call we can't reliably point to the error's
// span so just use the template's span as the error span (fixes #129503)
template_span
} else {
template_span.from_inner(InnerSpan::new(err.span.start, err.span.end))
};

let err_sp = span_in_template(err.span);

let msg = format!("invalid asm template string: {}", err.description);
let mut e = ecx.dcx().struct_span_err(err_sp, msg);
Expand All @@ -397,8 +404,7 @@ fn expand_preparsed_asm(
e.note(note);
}
if let Some((label, span)) = err.secondary_label {
let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end));
e.span_label(err_sp, label);
e.span_label(span_in_template(span), label);
}
let guar = e.emit();
return ExpandResult::Ready(Err(guar));
Expand Down Expand Up @@ -477,8 +483,7 @@ fn expand_preparsed_asm(
ecx.dcx()
.create_err(errors::AsmNoMatchedArgumentName {
name: name.to_owned(),
span: template_span
.from_inner(InnerSpan::new(span.start, span.end)),
span: span_in_template(span),
})
.emit();
None
Expand All @@ -490,11 +495,7 @@ fn expand_preparsed_asm(
let mut chars = arg.format.ty.chars();
let mut modifier = chars.next();
if chars.next().is_some() {
let span = arg
.format
.ty_span
.map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
.unwrap_or(template_sp);
let span = arg.format.ty_span.map(span_in_template).unwrap_or(template_sp);
ecx.dcx().emit_err(errors::AsmModifierInvalid { span });
modifier = None;
}
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_builtin_macros/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,18 @@ pub(crate) enum InvalidFormatStringSuggestion {
#[primary_span]
span: Span,
},

#[suggestion(
"use rust debug printing macro",
code = "{replacement}",
style = "verbose",
applicability = "machine-applicable"
)]
UseRustDebugPrintingMacro {
#[primary_span]
macro_span: Span,
replacement: String,
},
}

#[derive(Diagnostic)]
Expand Down
20 changes: 19 additions & 1 deletion compiler/rustc_builtin_macros/src/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ fn make_format_args(
ecx: &mut ExtCtxt<'_>,
input: MacroInput,
append_newline: bool,
macro_span: Span,
) -> ExpandResult<Result<FormatArgs, ErrorGuaranteed>, ()> {
let msg = "format argument must be a string literal";
let unexpanded_fmt_span = input.fmtstr.span;
Expand Down Expand Up @@ -333,6 +334,23 @@ fn make_format_args(
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span });
}
parse::Suggestion::UseRustDebugPrintingMacro => {
// This targets `println!("{=}", x);` and `println!("{0=}", x);`
if let [arg] = args.all_args() {
let expr_span = arg.expr.span;
if let Ok(expr_snippet) = ecx.source_map().span_to_snippet(expr_span) {
let replacement = format!("{}!({})", "dbg", expr_snippet);

let call_span = macro_span.source_callsite();
e.sugg_ = Some(
errors::InvalidFormatStringSuggestion::UseRustDebugPrintingMacro {
macro_span: call_span,
replacement,
},
);
}
}
}
}
let guar = ecx.dcx().emit_err(e);
return ExpandResult::Ready(Err(guar));
Expand Down Expand Up @@ -1048,7 +1066,7 @@ fn expand_format_args_impl<'cx>(
sp = ecx.with_def_site_ctxt(sp);
ExpandResult::Ready(match parse_args(ecx, sp, tts) {
Ok(input) => {
let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl) else {
let ExpandResult::Ready(mac) = make_format_args(ecx, input, nl, sp) else {
return ExpandResult::Retry(());
};
match mac {
Expand Down
18 changes: 18 additions & 0 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,24 @@ pub(crate) struct ExpectedExpressionFoundLet {
pub comparison: Option<MaybeComparison>,
}

#[derive(Diagnostic)]
#[diag("let-chain with missing `let`")]
pub(crate) struct LetChainMissingLet {
#[primary_span]
pub span: Span,
#[label("expected `let` expression, found assignment")]
pub label_span: Span,
#[label("let expression later in the condition")]
pub rhs_span: Span,
#[suggestion(
"add `let` before the expression",
applicability = "maybe-incorrect",
code = "let ",
style = "verbose"
)]
pub sug_span: Span,
}

#[derive(Diagnostic)]
#[diag("`||` operators are not supported in let chain conditions")]
pub(crate) struct OrInLetChain {
Expand Down
47 changes: 46 additions & 1 deletion compiler/rustc_parse/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4282,7 +4282,52 @@ impl MutVisitor for CondChecker<'_> {
mut_visit::walk_expr(self, e);
self.forbid_let_reason = forbid_let_reason;
}
ExprKind::Assign(ref lhs, _, span) => {
ExprKind::Assign(ref lhs, ref rhs, span) => {
if let ExprKind::Call(_, _) = &lhs.kind {
fn get_path_from_rhs(e: &Expr) -> Option<(u32, &Path)> {
fn inner(e: &Expr, depth: u32) -> Option<(u32, &Path)> {
match &e.kind {
ExprKind::Binary(_, lhs, _) => inner(lhs, depth + 1),
ExprKind::Path(_, path) => Some((depth, path)),
_ => None,
}
}

inner(e, 0)
}

if let Some((depth, path)) = get_path_from_rhs(rhs) {
// For cases like if Some(_) = x && let Some(_) = y && let Some(_) = z
// This return let Some(_) = y expression
fn find_let_some(expr: &Expr) -> Option<&Expr> {
match &expr.kind {
ExprKind::Let(..) => Some(expr),

ExprKind::Binary(op, lhs, rhs) if op.node == BinOpKind::And => {
find_let_some(lhs).or_else(|| find_let_some(rhs))
}

_ => None,
}
}

let expr_span = lhs.span.to(path.span);

if let Some(later_rhs) = find_let_some(rhs)
&& depth > 0
{
let guar = self.parser.dcx().emit_err(errors::LetChainMissingLet {
span: lhs.span,
label_span: expr_span,
rhs_span: later_rhs.span,
sug_span: lhs.span.shrink_to_lo(),
});

self.found_incorrect_let_chain = Some(guar);
}
}
}

let forbid_let_reason = self.forbid_let_reason;
self.forbid_let_reason = Some(errors::ForbiddenLetReason::OtherForbidden);
let missing_let = self.missing_let;
Expand Down
25 changes: 25 additions & 0 deletions compiler/rustc_parse_format/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ pub enum Suggestion {
/// Add missing colon:
/// `format!("{foo?}")` -> `format!("{foo:?}")`
AddMissingColon(Range<usize>),
/// Use Rust format string:
/// `format!("{x=}")` -> `dbg!(x)`
UseRustDebugPrintingMacro,
}

/// The parser structure for interpreting the input format string. This is
Expand Down Expand Up @@ -462,6 +465,7 @@ impl<'input> Parser<'input> {
('?', _) => self.suggest_format_debug(),
('<' | '^' | '>', _) => self.suggest_format_align(c),
(',', _) => self.suggest_unsupported_python_numeric_grouping(),
('=', '}') => self.suggest_rust_debug_printing_macro(),
_ => self.suggest_positional_arg_instead_of_captured_arg(arg),
}
}
Expand Down Expand Up @@ -871,6 +875,27 @@ impl<'input> Parser<'input> {
}
}

fn suggest_rust_debug_printing_macro(&mut self) {
if let Some((range, _)) = self.consume_pos('=') {
self.errors.insert(
0,
ParseError {
description:
"python's f-string debug `=` is not supported in rust, use `dbg(x)` instead"
.to_owned(),
note: Some(format!("to print `{{`, you can escape it using `{{{{`",)),
label: "expected `}`".to_owned(),
span: range,
secondary_label: self
.last_open_brace
.clone()
.map(|sp| ("because of this opening brace".to_owned(), sp)),
suggestion: Suggestion::UseRustDebugPrintingMacro,
},
);
}
}

fn suggest_format_align(&mut self, alignment: char) {
if let Some((range, _)) = self.consume_pos(alignment) {
self.errors.insert(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_target/src/callconv/x86_win64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ where
BackendRepr::ScalableVector { .. } => panic!("scalable vectors are unsupported"),
BackendRepr::Scalar(scalar) => {
if is_ret && matches!(scalar.primitive(), Primitive::Int(Integer::I128, _)) {
if cx.target_spec().rustc_abi == Some(RustcAbi::X86Softfloat) {
if cx.target_spec().rustc_abi == Some(RustcAbi::Softfloat) {
// Use the native `i128` LLVM type for the softfloat ABI -- in other words, adjust nothing.
} else {
// `i128` is returned in xmm0 by Clang and GCC
Expand Down
16 changes: 12 additions & 4 deletions compiler/rustc_target/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ macro_rules! target_spec_enum {
pub enum $Name:ident {
$(
$( #[$variant_attr:meta] )*
$Variant:ident = $string:literal,
$Variant:ident = $string:literal $(,$alias:literal)* ,
)*
}
parse_error_type = $parse_error_type:literal;
Expand All @@ -88,6 +88,7 @@ macro_rules! target_spec_enum {
$(
$( #[$variant_attr] )*
#[serde(rename = $string)] // for JSON schema generation only
$( #[serde(alias = $alias)] )*
$Variant,
)*
}
Expand All @@ -97,7 +98,10 @@ macro_rules! target_spec_enum {

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
$( $string => Self::$Variant, )*
$(
$string => Self::$Variant,
$($alias => Self::$Variant,)*
)*
_ => {
let all = [$( concat!("'", $string, "'") ),*].join(", ");
return Err(format!("invalid {}: '{s}'. allowed values: {all}", $parse_error_type));
Expand All @@ -123,7 +127,7 @@ macro_rules! target_spec_enum {
pub enum $Name:ident {
$(
$( #[$variant_attr:meta] )*
$Variant:ident = $string:literal,
$Variant:ident = $string:literal $(,$alias:literal)* ,
)*
}
$( #[$other_variant_attr:meta] )*
Expand All @@ -134,6 +138,7 @@ macro_rules! target_spec_enum {
pub enum $Name {
$(
$( #[$variant_attr:meta] )*
$( #[serde(alias = $alias)] )*
$Variant,
)*
/// The vast majority of the time, the compiler deals with a fixed
Expand Down Expand Up @@ -165,7 +170,10 @@ macro_rules! target_spec_enum {

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
$( $string => Self::$Variant, )*
$(
$string => Self::$Variant,
$($alias => Self::$Variant,)*
)*
_ => Self::$OtherVariant(s.to_owned().into()),
})
}
Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1005,8 +1005,8 @@ crate::target_spec_enum! {
pub enum RustcAbi {
/// On x86-32 only: make use of SSE and SSE2 for ABI purposes.
X86Sse2 = "x86-sse2",
/// On x86-32/64 only: do not use any FPU or SIMD registers for the ABI.
X86Softfloat = "x86-softfloat",
/// On x86-32/64 and S390x: do not use any FPU or SIMD registers for the ABI.
Softfloat = "softfloat", "x86-softfloat",
}

parse_error_type = "rustc abi";
Expand Down Expand Up @@ -1460,6 +1460,7 @@ supported_targets! {
("powerpc64le-unknown-linux-gnu", powerpc64le_unknown_linux_gnu),
("powerpc64le-unknown-linux-musl", powerpc64le_unknown_linux_musl),
("s390x-unknown-linux-gnu", s390x_unknown_linux_gnu),
("s390x-unknown-none-softfloat", s390x_unknown_none_softfloat),
("s390x-unknown-linux-musl", s390x_unknown_linux_musl),
("sparc-unknown-linux-gnu", sparc_unknown_linux_gnu),
("sparc64-unknown-linux-gnu", sparc64_unknown_linux_gnu),
Expand Down Expand Up @@ -3204,10 +3205,10 @@ impl Target {
Arch::X86,
"`x86-sse2` ABI is only valid for x86-32 targets"
),
RustcAbi::X86Softfloat => check_matches!(
RustcAbi::Softfloat => check_matches!(
self.arch,
Arch::X86 | Arch::X86_64,
"`x86-softfloat` ABI is only valid for x86 targets"
Arch::X86 | Arch::X86_64 | Arch::S390x,
"`softfloat` ABI is only valid for x86 and s390x targets"
),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub(crate) fn target() -> Target {
// If you initialize FP units yourself, you can override these flags with custom linker
// arguments, thus giving you access to full MMX/SSE acceleration.
base.features = "-mmx,-sse,+soft-float".into();
base.rustc_abi = Some(RustcAbi::X86Softfloat);
base.rustc_abi = Some(RustcAbi::Softfloat);

// Turn off DWARF. This fixes an lld warning, "section name .debug_frame is longer than 8
// characters and will use a non-standard string table". That section will not be created if
Expand Down
Loading
Loading