Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 8 additions & 8 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
let spans = sess.psess.gated_spans.spans.borrow();
macro_rules! gate_all {
($feature:ident, $explain:literal $(, $help:literal)?) => {
for &span in spans.get(&sym::$feature).into_iter().flatten() {
for &span in spans.get(&sym::$feature).into_flat_iter() {
gate!(visitor, $feature, span, $explain $(, $help)?);
}
};
Expand Down Expand Up @@ -527,13 +527,13 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
);

// `associated_const_equality` will be stabilized as part of `min_generic_const_args`.
for &span in spans.get(&sym::associated_const_equality).into_iter().flatten() {
for &span in spans.get(&sym::associated_const_equality).into_flat_iter() {
gate!(visitor, min_generic_const_args, span, "associated const equality is incomplete");
}

// `mgca_type_const_syntax` is part of `min_generic_const_args` so if
// either or both are enabled we don't need to emit a feature error.
for &span in spans.get(&sym::mgca_type_const_syntax).into_iter().flatten() {
for &span in spans.get(&sym::mgca_type_const_syntax).into_flat_iter() {
if visitor.features.min_generic_const_args()
|| visitor.features.mgca_type_const_syntax()
|| span.allows_unstable(sym::min_generic_const_args)
Expand Down Expand Up @@ -561,13 +561,13 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
// it does **not** mean "`T` doesn't implement `Bound` (positively or negatively)"!
// The latter would be a SemVer hazard!
if !sess.opts.unstable_opts.internal_testing_features || !visitor.features.negative_bounds() {
for &span in spans.get(&sym::negative_bounds).into_iter().flatten() {
for &span in spans.get(&sym::negative_bounds).into_flat_iter() {
sess.dcx().emit_err(diagnostics::NegativeBoundUnsupported { span });
}
}

if !visitor.features.never_patterns() {
for &span in spans.get(&sym::never_patterns).into_iter().flatten() {
for &span in spans.get(&sym::never_patterns).into_flat_iter() {
if span.allows_unstable(sym::never_patterns) {
continue;
}
Expand All @@ -585,7 +585,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
}

// Yield exprs can be enabled either by `yield_expr`, by `coroutines` or by `gen_blocks`.
for &span in spans.get(&sym::yield_expr).into_iter().flatten() {
for &span in spans.get(&sym::yield_expr).into_flat_iter() {
if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines))
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
&& (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr))
Expand All @@ -607,7 +607,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {

macro_rules! soft_gate_all_legacy_dont_use {
($feature:ident, $explain:literal) => {
for &span in spans.get(&sym::$feature).into_iter().flatten() {
for &span in spans.get(&sym::$feature).into_flat_iter() {
if !visitor.features.$feature() && !span.allows_unstable(sym::$feature) {
feature_warn(&visitor.sess, sym::$feature, span, $explain);
}
Expand All @@ -625,7 +625,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
soft_gate_all_legacy_dont_use!(try_blocks, "`try` blocks are unstable");
// tidy-alphabetical-end

for &span in spans.get(&sym::min_specialization).into_iter().flatten() {
for &span in spans.get(&sym::min_specialization).into_flat_iter() {
if !visitor.features.specialization()
&& !visitor.features.min_specialization()
&& !span.allows_unstable(sym::specialization)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#![feature(deref_patterns)]
#![feature(iter_intersperse)]
#![feature(iter_is_partitioned)]
#![feature(option_into_flat_iter)]
// tidy-alphabetical-end

pub mod ast_validation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ pub(crate) struct OnTypeErrorParser {
impl OnTypeErrorParser {
fn parse<'sess>(&mut self, cx: &mut AcceptContext<'_, 'sess>, args: &ArgParser, mode: Mode) {
if !cx.features().diagnostic_on_type_error() {
// `UnknownDiagnosticAttribute` is emitted in rustc_resolve/macros.rs
args.ignore_args();
return;
}

Expand Down
5 changes: 2 additions & 3 deletions compiler/rustc_borrowck/src/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,9 +476,8 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> {
.borrow_set
.local_map
.get(&place.local)
.into_iter()
.flat_map(|bs| bs.iter())
.copied();
.map(|bs| bs.iter().copied())
.into_flat_iter();

// If the borrowed place is a local with no projections, all other borrows of this
// local must conflict. This is purely an optimization so we don't have to call
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#![feature(file_buffered)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(option_into_flat_iter)]
#![feature(rustc_attrs)]
#![feature(stmt_expr_attributes)]
#![feature(try_blocks)]
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_borrowck/src/polonius/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl LocalizedConstraintGraph {
// The physical edges present at this node are:
//
// 1. the typeck edges that flow from region to region *at this point*.
for &succ in self.edges.get(&node).into_iter().flatten() {
for &succ in self.edges.get(&node).into_flat_iter() {
let succ = LocalizedNode { region: succ, point: node.point };
successor_found(succ);
}
Expand Down Expand Up @@ -229,7 +229,7 @@ impl LocalizedConstraintGraph {
}

// And finally, we have the logical edges, materialized at this point.
for &logical_succ in self.logical_edges.get(&node.region).into_iter().flatten() {
for &logical_succ in self.logical_edges.get(&node.region).into_flat_iter() {
let succ = LocalizedNode { region: logical_succ, point: node.point };
successor_found(succ);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub(super) fn apply_member_constraints<'tcx>(
rcx.scc_values.add_region(scc_a, scc_b);
}

for defining_use in member_constraints.get(&scc_a).into_iter().flatten() {
for defining_use in member_constraints.get(&scc_a).into_flat_iter() {
apply_member_constraint(rcx, scc_a, &defining_use.arg_regions);
}
}
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_borrowck/src/region_infer/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ impl LivenessValues {

/// Returns an iterator of all the points where `region` is live.
fn live_points(&self, region: RegionVid) -> impl Iterator<Item = PointIndex> {
self.point_liveness(region).into_iter().flat_map(|set| set.iter())
self.point_liveness(region).map(|set| set.iter()).into_flat_iter()
}

/// For debugging purposes, returns a pretty-printed string of the points where the `region` is
Expand Down Expand Up @@ -348,13 +348,13 @@ impl<'tcx, N: Idx> RegionValues<'tcx, N> {
pub(crate) fn locations_outlived_by(&self, r: N) -> impl Iterator<Item = Location> {
self.points
.row(r)
.into_iter()
.flat_map(move |set| set.iter().map(move |p| self.location_map.to_location(p)))
.map(move |set| set.iter().map(move |p| self.location_map.to_location(p)))
.into_flat_iter()
}

/// Returns just the universal regions that are contained in a given region's value.
pub(crate) fn universal_regions_outlived_by(&self, r: N) -> impl Iterator<Item = RegionVid> {
self.free_regions.row(r).into_iter().flat_map(|set| set.iter())
self.free_regions.row(r).map(|set| set.iter()).into_flat_iter()
}

/// Returns all the elements contained in a given region's value.
Expand All @@ -364,8 +364,8 @@ impl<'tcx, N: Idx> RegionValues<'tcx, N> {
) -> impl Iterator<Item = ty::PlaceholderRegion<'tcx>> {
self.placeholders
.row(r)
.into_iter()
.flat_map(|set| set.iter())
.map(|set| set.iter())
.into_flat_iter()
.map(move |p| self.placeholder_indices.lookup_placeholder(p))
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -928,7 +928,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
self.super_local_decl(local, local_decl);

for user_ty in
local_decl.user_ty.as_deref().into_iter().flat_map(UserTypeProjections::projections)
local_decl.user_ty.as_deref().map(UserTypeProjections::projections).into_flat_iter()
{
let span = self.user_type_annotations[user_ty.base].span;

Expand Down
9 changes: 2 additions & 7 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::ffi::c_uint;
use std::{assert_matches, iter, ptr};

use rustc_abi::{
AddressSpace, Align, BackendRepr, CVariadicStatus, Float, HasDataLayout, Integer,
NumScalableVectors, Primitive, Size, WrappingRange,
AddressSpace, Align, BackendRepr, CVariadicStatus, Float, HasDataLayout, NumScalableVectors,
Primitive, Size, WrappingRange,
};
use rustc_codegen_ssa::RetagInfo;
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
Expand Down Expand Up @@ -315,11 +315,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
Primitive::Pointer(_) => {
// Pointers are always OK.
}
Primitive::Int(Integer::I128, _) => {
// FIXME: maybe we should support these? At least on 32-bit powerpc
// the logic in LLVM does not handle i128 correctly though.
bug!("the va_arg intrinsic does not support `i128`/`u128`")
}
Primitive::Int(..) => {
let int_width = self.cx().size_of(result_layout.ty).bits();
let target_c_int_width = self.cx().sess().target.options.c_int_width;
Expand Down
81 changes: 58 additions & 23 deletions compiler/rustc_codegen_llvm/src/va_arg.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use rustc_abi::{Align, BackendRepr, CVariadicStatus, Endian, HasDataLayout, Primitive, Size};
use rustc_codegen_ssa::MemFlags;
use rustc_abi::{
Align, BackendRepr, CVariadicStatus, Endian, Float, HasDataLayout, Integer, Primitive, Size,
};
use rustc_codegen_ssa::common::IntPredicate;
use rustc_codegen_ssa::mir::operand::OperandRef;
use rustc_codegen_ssa::traits::{
Expand Down Expand Up @@ -77,6 +78,35 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>(
}
}

/// Some backends apply special alignment rules to c-variadic arguments.
fn get_param_type_alignment<'ll, 'tcx>(
bx: &mut Builder<'_, 'll, 'tcx>,
layout: TyAndLayout<'tcx>,
) -> Align {
let BackendRepr::Scalar(scalar) = layout.backend_repr else {
bug!("unexpected backend repr {:?}", layout.backend_repr);
};

match bx.cx.tcx.sess.target.arch {
Arch::PowerPC64 => match scalar.primitive() {
Primitive::Int(integer, _) => match integer {
Integer::I8 | Integer::I16 => unreachable!(),
Integer::I32 | Integer::I64 => { /* fall through */ }
Integer::I128 => return Align::EIGHT,
},
Primitive::Float(float) => match float {
Float::F16 | Float::F32 => unreachable!(),
Float::F64 => { /* fall through */ }
Float::F128 => return Align::from_bytes(16).unwrap(),
},
Primitive::Pointer(_) => { /* fall through */ }
},
_ => { /* fall through */ }
}

layout.align.abi
}

enum PassMode {
Direct,
Indirect,
Expand Down Expand Up @@ -136,23 +166,23 @@ fn emit_ptr_va_arg<'ll, 'tcx>(
(
bx.cx.layout_of(Ty::new_imm_ptr(bx.cx.tcx, target_ty)).llvm_type(bx.cx),
bx.cx.data_layout().pointer_size(),
bx.cx.data_layout().pointer_align(),
bx.cx.data_layout().pointer_align().abi,
)
} else {
(layout.llvm_type(bx.cx), layout.size, layout.align)
(layout.llvm_type(bx.cx), layout.size, get_param_type_alignment(bx, layout))
};
let (addr, addr_align) = emit_direct_ptr_va_arg(
bx,
list,
size,
align.abi,
align,
slot_size,
allow_higher_align,
force_right_adjust,
);
if indirect {
let tmp_ret = bx.load(llty, addr, addr_align);
bx.load(layout.llvm_type(bx.cx), tmp_ret, align.abi)
bx.load(layout.llvm_type(bx.cx), tmp_ret, align)
} else {
bx.load(llty, addr, addr_align)
}
Expand Down Expand Up @@ -585,8 +615,10 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
// registers. In the case: l->gp_offset > 48 - num_gp * 8 or
// l->fp_offset > 176 - num_fp * 16 go to step 7.

// We support x86_64-unknown-linux-gnux32 which uses 4-byte pointers.
let unsigned_int_offset = 4;
let ptr_offset = 8;
let ptr_offset = bx.tcx().data_layout.pointer_size().bytes();

let gp_offset_ptr = va_list_addr;
let fp_offset_ptr = bx.inbounds_ptradd(va_list_addr, bx.cx.const_usize(unsigned_int_offset));

Expand Down Expand Up @@ -660,7 +692,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
let reg_hi_addr = bx.inbounds_ptradd(reg_lo_addr, bx.const_i32(16));

let align = layout.layout.align().abi;
let tmp = bx.alloca(layout.layout.size(), align);
let tmp = bx.alloca(layout.size, layout.align.abi);

let reg_lo = bx.load(ty_lo, reg_lo_addr, align_lo);
let reg_hi = bx.load(ty_hi, reg_hi_addr, align_hi);
Expand All @@ -683,7 +715,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>(
Primitive::Int(_, _) | Primitive::Pointer(_) => (gp_addr, fp_addr),
};

let tmp = bx.alloca(layout.layout.size(), layout.layout.align().abi);
let tmp = bx.alloca(layout.size, layout.align.abi);

let reg_lo = bx.load(ty_lo, reg_lo_addr, align_lo);
let reg_hi = bx.load(ty_hi, reg_hi_addr, align_hi);
Expand Down Expand Up @@ -751,16 +783,12 @@ fn copy_to_temporary_if_more_aligned<'ll, 'tcx>(
src_align: Align,
) -> &'ll Value {
if layout.layout.align.abi > src_align {
let tmp = bx.alloca(layout.layout.size(), layout.layout.align().abi);
bx.memcpy(
tmp,
layout.layout.align.abi,
reg_addr,
src_align,
bx.const_u32(layout.layout.size().bytes() as u32),
MemFlags::empty(),
None,
);
assert!(layout.ty.is_integral());

// A memcpy below optimizes poorly for 128-bit integers.
let tmp = bx.alloca(layout.size, layout.align.abi);
let val = bx.load(layout.llvm_type(bx), reg_addr, src_align);
bx.store(val, tmp, layout.align.abi);
tmp
} else {
reg_addr
Expand All @@ -782,9 +810,14 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
// byte boundary if alignment needed by type exceeds 8 byte boundary.
// It isn't stated explicitly in the standard, but in practice we use
// alignment greater than 16 where necessary.
if layout.layout.align.bytes() > 8 {
unreachable!("all instances of VaArgSafe have an alignment <= 8");
}
// The AMD64 psABI leaves unspecified what to do for alignments above 16, but
// this behavior for 32+ alignment matches clang.
// It currently (2026 July) can only occur for 16-byte-aligned types.
let overflow_arg_area_v = if layout.layout.align.bytes() > 8 {
round_pointer_up_to_alignment(bx, overflow_arg_area_v, layout.layout.align.abi)
} else {
overflow_arg_area_v
};

// AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
let mem_addr = overflow_arg_area_v;
Expand Down Expand Up @@ -1071,7 +1104,8 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
Arch::AArch64 => emit_aapcs_va_arg(bx, addr, target_ty),
Arch::Arm => {
// Types wider than 16 bytes are not currently supported. Clang has special logic for
// such types, but `VaArgSafe` is not implemented for any type that is this large.
// such types, but `VaArgSafe` is not implemented for any type that is this large on
// arm (i.e. 32-bit) targets.
assert!(bx.cx.size_of(target_ty).bytes() <= 16);

emit_ptr_va_arg(
Expand All @@ -1093,6 +1127,7 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
PassMode::Direct,
SlotSize::Bytes8,
AllowHigherAlign::Yes,
// ForceRightAdjust only takes effect on big-endian architectures.
ForceRightAdjust::Yes,
),
Arch::RiscV32 if target.llvm_abiname == LlvmAbi::Ilp32e => {
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_codegen_ssa/src/assert_module_sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
fn check_attrs(&mut self, attrs: &[hir::Attribute]) {
for &(span, cgu_fields) in find_attr!(attrs,
RustcCguTestAttr(e) => e)
.into_iter()
.flatten()
.into_flat_iter()
{
let (expected_reuse, comp_kind) = match cgu_fields {
CguFields::PartitionReused { .. } => (CguReuse::PreLto, ComparisonKind::AtLeast),
Expand Down
Loading
Loading