Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fb0210d
PowerPC inline ASM: Fix scalar floats being in the wrong vector lane …
beetrees Aug 3, 2026
3d9bfe9
rustdoc: use anonymous constant for primitives/keywords/attribute docs
mejrs Aug 4, 2026
6a4b141
ensure anon consts themselves are not documented
mejrs Aug 11, 2026
742c085
Use 2 word unwinder_private_data on Emscripten
bjorn3 Jul 19, 2026
1890b82
Move wasi libunwind link block to crate root
bjorn3 Aug 3, 2026
e08ce7f
Avoid defining dummy personality function for Motor OS
bjorn3 Jul 24, 2026
37831ee
Use dummy panic_unwind impl for Hermit
bjorn3 Jul 28, 2026
5b66cc1
add `Complex` type
folkertdev Jul 4, 2026
d7ec103
update hygiene test
folkertdev Aug 12, 2026
592e138
define `Ty::is_complex`
folkertdev Aug 12, 2026
05e8259
add `complex-abi.rs` test
folkertdev Jul 6, 2026
34fab67
add CHECK lines and revisions
folkertdev Jul 6, 2026
4213ac7
disable most revisions
folkertdev Jul 6, 2026
5e8cc87
Implement and test x86_64 Complex
folkertdev Jul 6, 2026
daf4a0e
`Complex` return on `x86`
folkertdev Jul 21, 2026
fd86d6d
x86_64-win: Enable f128 on LLVM 23+
tgross35 Jul 7, 2026
55650a2
Add regression test for try block label suggestions
chenyukang Aug 13, 2026
54a6391
Fix invalid suggestion from try unlabled block
chenyukang Aug 13, 2026
dd09da0
Rollup merge of #158918 - tgross35:win64-f128-updates, r=folkertdev
JonathanBrouwer Aug 13, 2026
4c917e8
Rollup merge of #160288 - mejrs:anon_const_attr_docs, r=GuillaumeGomez
JonathanBrouwer Aug 13, 2026
ea470f2
Rollup merge of #160440 - bjorn3:refactor_unwind4, r=Mark-Simulacrum
JonathanBrouwer Aug 13, 2026
e0ff20b
Rollup merge of #160441 - beetrees:inline-asm-fix-powerpc64le, r=Amanieu
JonathanBrouwer Aug 13, 2026
8e9e1c5
Rollup merge of #158885 - folkertdev:complex-layout, r=workingjubilee
JonathanBrouwer Aug 13, 2026
851e090
Rollup merge of #161016 - chenyukang:yukang-fix-160987-try-block-labe…
JonathanBrouwer Aug 13, 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
28 changes: 28 additions & 0 deletions compiler/rustc_abi/src/layout/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display {
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
fn is_complex_number(this: TyAndLayout<'a, Self>, cx: &C) -> bool;
fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool;
/// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
Expand Down Expand Up @@ -227,6 +228,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
Ty::is_transparent(self)
}

pub fn is_complex_number<C>(self, cx: &C) -> bool
where
Ty: TyAbiInterface<'a, C> + Copy,
{
Ty::is_complex_number(self.peel_transparent_wrappers(cx), cx)
}

pub fn is_scalable_vector<C>(self) -> bool
where
Ty: TyAbiInterface<'a, C>,
Expand Down Expand Up @@ -291,6 +299,26 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
found
}

pub fn complex_float<C>(&self, cx: &C) -> Option<Float>
where
Ty: TyAbiInterface<'a, C> + Copy,
{
if !Ty::is_complex_number(*self, cx) {
return None;
}

let BackendRepr::ScalarPair { a, b, .. } = self.backend_repr else {
return None;
};

debug_assert_eq!(a, b);

match a.primitive() {
Primitive::Float(f) => Some(f),
_ => None,
}
}

/// Whether this type/layout has any padding that is dependent on a variant, i.e. has bytes that
/// are padding for some, but not all, valid values of this type.
pub fn has_variant_dependent_padding<C>(&self, cx: &C) -> bool
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_ir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ language_item_table! {
VaArgSafe, sym::va_arg_safe, va_arg_safe, Target::Trait, GenericRequirement::None;
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;

Complex, sym::complex, complex, Target::Struct, GenericRequirement::Exact(1);

Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
DerefMut, sym::deref_mut, deref_mut_trait, Target::Trait, GenericRequirement::Exact(0);
DerefPure, sym::deref_pure, deref_pure_trait, Target::Trait, GenericRequirement::Exact(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1132,7 +1132,7 @@ pub(crate) struct RustcDocPrimitiveParser;

impl SingleAttributeParser for RustcDocPrimitiveParser {
const PATH: &[Symbol] = &[sym::rustc_doc_primitive];
const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Mod)]);
const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Const)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name");
const STABILITY: AttributeStability = unstable!(
rustc_attrs,
Expand Down
56 changes: 23 additions & 33 deletions compiler/rustc_codegen_llvm/src/asm.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::assert_matches;
use std::fmt::Write;

use rustc_abi::{BackendRepr, Float, Integer, Primitive, Scalar, Size};
use rustc_abi::{BackendRepr, Endian, Float, Integer, Primitive, Scalar, Size};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_codegen_ssa::mir::operand::OperandValue;
use rustc_codegen_ssa::traits::*;
Expand All @@ -12,6 +12,7 @@ use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::{bug, span_bug};
use rustc_span::{Pos, Span, Symbol, sym};
use rustc_target::asm::*;
use rustc_target::spec::HasTargetSpec;
use smallvec::SmallVec;
use tracing::debug;

Expand Down Expand Up @@ -1244,24 +1245,16 @@ fn llvm_fixup_input<'ll, 'tcx>(
(
PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
BackendRepr::Scalar(s),
) if s.primitive() == Primitive::Float(Float::F32) => {
let value = bx.insert_element(
bx.const_undef(bx.type_vector(bx.type_f32(), 4)),
) if let Primitive::Float(float @ (Float::F32 | Float::F64)) = s.primitive() => {
let num_lanes = 16 / float.size().bytes();
bx.insert_element(
bx.const_undef(bx.type_vector(bx.type_from_float(float), num_lanes)),
value,
bx.const_usize(0),
);
bx.bitcast(value, bx.type_vector(bx.type_f32(), 4))
}
(
PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
BackendRepr::Scalar(s),
) if s.primitive() == Primitive::Float(Float::F64) => {
let value = bx.insert_element(
bx.const_undef(bx.type_vector(bx.type_f64(), 2)),
value,
bx.const_usize(0),
);
bx.bitcast(value, bx.type_vector(bx.type_f64(), 2))
bx.const_usize(match bx.target_spec().endian {
Endian::Little => num_lanes - 1,
Endian::Big => 0,
}),
)
}
_ => value,
}
Expand Down Expand Up @@ -1416,16 +1409,15 @@ fn llvm_fixup_output<'ll, 'tcx>(
(
PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
BackendRepr::Scalar(s),
) if s.primitive() == Primitive::Float(Float::F32) => {
let value = bx.bitcast(value, bx.type_vector(bx.type_f32(), 4));
bx.extract_element(value, bx.const_usize(0))
}
(
PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
BackendRepr::Scalar(s),
) if s.primitive() == Primitive::Float(Float::F64) => {
let value = bx.bitcast(value, bx.type_vector(bx.type_f64(), 2));
bx.extract_element(value, bx.const_usize(0))
) if let Primitive::Float(float @ (Float::F32 | Float::F64)) = s.primitive() => {
let num_lanes = 16 / float.size().bytes();
bx.extract_element(
value,
bx.const_usize(match bx.target_spec().endian {
Endian::Little => num_lanes - 1,
Endian::Big => 0,
}),
)
}
_ => value,
}
Expand Down Expand Up @@ -1566,11 +1558,9 @@ fn llvm_fixup_output_type<'ll, 'tcx>(
(
PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
BackendRepr::Scalar(s),
) if s.primitive() == Primitive::Float(Float::F32) => cx.type_vector(cx.type_f32(), 4),
(
PowerPC(PowerPCInlineAsmRegClass::vreg | PowerPCInlineAsmRegClass::vsreg),
BackendRepr::Scalar(s),
) if s.primitive() == Primitive::Float(Float::F64) => cx.type_vector(cx.type_f64(), 2),
) if let Primitive::Float(float @ (Float::F32 | Float::F64)) = s.primitive() => {
cx.type_vector(cx.type_from_float(float), 16 / float.size().bytes())
}
_ => layout.llvm_type(cx),
}
}
9 changes: 6 additions & 3 deletions compiler/rustc_codegen_llvm/src/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,8 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
cfg.has_reliable_f16 = match (target_arch, target_os) {
// Unsupported <https://github.com/llvm/llvm-project/issues/94434> (fixed in llvm22)
(Arch::Arm64EC, _) if major < 22 => false,
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> resolved in GCC 16
// but our toolchain hasn't been updated.
(Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != CfgAbi::Llvm => {
false
}
Expand All @@ -401,8 +402,10 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) {
(Arch::PowerPC | Arch::PowerPC64, _) => false,
// ABI unsupported <https://github.com/llvm/llvm-project/issues/41838> (fixed in llvm22)
(Arch::Sparc, _) if major < 22 => false,
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
(Arch::X86_64, Os::Windows) if *target_env == Env::Gnu && *target_abi != CfgAbi::Llvm => {
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054> (fixed in llvm23)
(Arch::X86_64, Os::Windows)
if *target_env == Env::Gnu && *target_abi != CfgAbi::Llvm && major < 23 =>
{
false
}
// There are no known problems on other platforms, so the only requirement is that symbols
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_hir_typeck/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -819,10 +819,13 @@ pub(crate) struct OutsideLoop<'a> {
applicability = "maybe-incorrect"
)]
pub(crate) struct OutsideLoopSuggestion {
#[suggestion_part(code = "'block: ")]
#[suggestion_part(code = "{block_prefix}")]
pub block_span: Span,
#[suggestion_part(code = " 'block")]
pub break_spans: Vec<Span>,
#[suggestion_part(code = " }}")]
pub wrap_end: Option<Span>,
pub block_prefix: &'static str,
}

#[derive(Diagnostic)]
Expand Down
29 changes: 21 additions & 8 deletions compiler/rustc_hir_typeck/src/loops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ enum Context {
kind: hir::CoroutineDesugaring,
source: hir::CoroutineSource,
},
UnlabeledBlock(Span),
UnlabeledBlock {
label_span: Span,
wrap_end: Option<Span>,
},
UnlabeledIfBlock(Span),
LabeledBlock,
/// E.g. The labeled block inside `['_'; 'block: { break 'block 1 + 2; }]`.
Expand All @@ -50,6 +53,7 @@ struct BlockInfo {
name: String,
spans: Vec<Span>,
suggs: Vec<Span>,
wrap_end: Option<Span>,
}

#[derive(PartialEq)]
Expand Down Expand Up @@ -118,7 +122,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
ck_loop.cx_stack.last(),
Some(&Normal)
| Some(&AnonConst)
| Some(&UnlabeledBlock(_))
| Some(&UnlabeledBlock { .. })
| Some(&UnlabeledIfBlock(_))
)
{
Expand Down Expand Up @@ -177,10 +181,16 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
None,
) if matches!(
self.cx_stack.last(),
Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock(_))
Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock { .. })
) =>
{
self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b));
// An unlabeled block targeted by `break` may comes from a `try` block.
// Since `try 'block: {}` is invalid, nest a labeled block inside its body.
let wrap_end = b.targeted_by_break.then(|| b.span.shrink_to_hi());
self.with_context(
UnlabeledBlock { label_span: b.span.shrink_to_lo(), wrap_end },
|v| v.visit_block(b),
);
}
hir::ExprKind::Break(break_destination, ref opt_expr) => {
if let Some(e) = opt_expr {
Expand Down Expand Up @@ -365,21 +375,22 @@ impl<'hir> CheckLoopVisitor<'hir> {
source,
});
}
UnlabeledBlock(block_span)
if br_cx_kind == BreakContextKind::Break && block_span.eq_ctxt(break_span) =>
UnlabeledBlock { label_span, wrap_end }
if br_cx_kind == BreakContextKind::Break && label_span.eq_ctxt(break_span) =>
{
let block = self.block_breaks.entry(block_span).or_insert_with(|| BlockInfo {
let block = self.block_breaks.entry(label_span).or_insert_with(|| BlockInfo {
name: br_cx_kind.to_string(),
spans: vec![],
suggs: vec![],
wrap_end,
});
block.spans.push(span);
block.suggs.push(break_span);
}
UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => {
self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1);
}
Normal | AnonConst | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) | ConstBlock => {
Normal | AnonConst | Fn | UnlabeledBlock { .. } | UnlabeledIfBlock(_) | ConstBlock => {
self.tcx.dcx().emit_err(OutsideLoop {
spans: vec![span],
name: &br_cx_kind.to_string(),
Expand Down Expand Up @@ -415,6 +426,8 @@ impl<'hir> CheckLoopVisitor<'hir> {
suggestion: Some(OutsideLoopSuggestion {
block_span: *s,
break_spans: block.suggs.clone(),
block_prefix: if block.wrap_end.is_some() { "{ 'block: " } else { "'block: " },
wrap_end: block.wrap_end,
}),
});
}
Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,20 @@ where
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
}

/// Does this type have a layout compatible with C `_Complex`?
///
/// The value must be of type `core::num::Complex<T>` where `T` is numeric.
fn is_complex_number(this: TyAndLayout<'tcx>, cx: &C) -> bool {
let ty::Adt(def, generic_args) = this.ty.kind() else { return false };

if !cx.tcx().is_lang_item(def.did(), LangItem::Complex) {
return false;
}

// Only Complex<{ float }> and Complex<{ integer }> have special layout.
generic_args.type_at(0).is_numeric()
}

fn is_scalable_vector(this: TyAndLayout<'tcx>) -> bool {
this.ty.is_scalable_vector()
}
Expand Down
19 changes: 6 additions & 13 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use rustc_session::lint::builtin::{
MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
};
use rustc_span::edition::Edition;
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym};
use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
use rustc_trait_selection::traits::{ObligationCtxt, TraitErrors};
Expand Down Expand Up @@ -1024,18 +1024,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
hir::Node::Item(item) => Some(&item.kind),
_ => None,
};
match item_kind {
Some(ItemKind::Mod(_, module)) => {
if !module.item_ids.is_empty() {
self.dcx()
.emit_err(diagnostics::DocKeywordAttributeEmptyMod { span, attr_name });
return;
}
}
_ => {
self.dcx().emit_err(diagnostics::DocKeywordAttributeNotMod { span, attr_name });
return;
}
if let Some(ItemKind::Const(ident, _gen, _ty, _rhs)) = item_kind
&& ident.name == kw::Underscore
{
} else {
self.dcx().emit_err(diagnostics::DocKeywordAttributeNotAnonConst { span, attr_name });
}
}

Expand Down
12 changes: 2 additions & 10 deletions compiler/rustc_passes/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,8 @@ pub(crate) struct DocAliasNotAnAlias {
}

#[derive(Diagnostic)]
#[diag("`#[doc({$attr_name} = \"...\")]` should be used on empty modules")]
pub(crate) struct DocKeywordAttributeEmptyMod {
#[primary_span]
pub span: Span,
pub attr_name: &'static str,
}

#[derive(Diagnostic)]
#[diag("`#[doc({$attr_name} = \"...\")]` should be used on modules")]
pub(crate) struct DocKeywordAttributeNotMod {
#[diag("`#[doc({$attr_name} = \"...\")]` should be used on anonymous constants")]
pub(crate) struct DocKeywordAttributeNotAnonConst {
#[primary_span]
pub span: Span,
pub attr_name: &'static str,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,7 @@ symbols! {
compiler_copy,
compiler_fence,
compiler_move,
complex,
concat,
concat_bytes,
conservative_impl_trait,
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_target/src/callconv/x86.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use rustc_abi::{
AddressSpace, Align, BackendRepr, HasDataLayout, Primitive, Reg, RegKind, TyAndLayout,
AddressSpace, Align, BackendRepr, Float, HasDataLayout, Primitive, Reg, RegKind, TyAndLayout,
};

use crate::callconv::{ArgAttribute, FnAbi, PassMode, TyAbiInterface};
Expand Down Expand Up @@ -32,7 +32,14 @@ where
// https://www.angelcode.com/dev/callconv/callconv.html
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
let t = cx.target_spec();
if t.abi_return_struct_as_int || opts.reg_struct_return {
if let Some(Float::F16) = fn_abi.ret.layout.complex_float(cx) {
// `_Complex _Float16` is returned as `<2 x half>`.
let kind = RegKind::Vector { hint_vector_elem: Primitive::Float(Float::F16) };
fn_abi.ret.cast_to(Reg { kind, size: fn_abi.ret.layout.size });
} else if t.abi_return_struct_as_int
|| opts.reg_struct_return
|| fn_abi.ret.layout.is_complex_number(cx)
{
// According to Clang, everyone but MSVC returns single-element
// float aggregates directly in a floating-point register.
if fn_abi.ret.layout.is_single_fp_element(cx) {
Expand Down
Loading
Loading