Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6ce0650
Add -Zinstrument-mcount=fentry to -Zinstrument-mcount
pmur Feb 16, 2026
bd757a6
llvm: use intrinsics for f16, f32 minimum/maximum
RalfJung Jun 23, 2026
e81423a
Allow either branch direction in ilog_known_base
HNO3Miracle Jun 24, 2026
db5a6a5
test(diagnostics): add baseline test for macro raw pointer deref
raushan728 Jun 24, 2026
011ac7a
fix(diagnostics): suppress raw ptr deref suggestion inside macros
raushan728 Jun 24, 2026
dad52d6
Add tests for defaults and infers in delegation's generics
aerooneqq Jun 25, 2026
4691890
LLVM 23: Adapt codegen test to moved assume
TimNN Jun 18, 2026
080c5d2
Generate synthetic generic args only for delegation's child segment
aerooneqq Jun 25, 2026
a2bb191
add `TyAndLayout::uninit_ranges`
folkertdev Jun 3, 2026
3cfdde8
zero out padding in cmse entry return values
folkertdev Jun 3, 2026
6ce8f07
zero out padding in cmse call arguments
folkertdev Jun 3, 2026
5f34c50
deduplicate `RangeSet`
folkertdev Jun 25, 2026
42e3291
Move part of the target checking for `#[may_dangle]` to the attribute…
JonathanBrouwer Jun 22, 2026
b442414
Update LLVM for Mach-O __LINKEDIT alignment fix.
goranmoomin Jun 25, 2026
87514a3
doc/unstable-book: document -Zinstrument-mcount
pmur Jun 22, 2026
9b1c041
Rollup merge of #158410 - goranmoomin:update-llvm-linkedit-align-1577…
jhpratt Jun 25, 2026
953dec1
Rollup merge of #157397 - folkertdev:cmse-clear-padding, r=davidtwco,…
jhpratt Jun 25, 2026
a82172d
Rollup merge of #158036 - pmur:murp/add-fentry, r=folkertdev
jhpratt Jun 25, 2026
e82d7b8
Rollup merge of #158330 - RalfJung:minimum-intrinsic, r=nikic
jhpratt Jun 25, 2026
1f9e9af
Rollup merge of #158359 - HNO3Miracle:fix-riscv-ilog-known-base, r=pe…
jhpratt Jun 25, 2026
3e2c952
Rollup merge of #158067 - TimNN:moved-assume, r=dianqk
jhpratt Jun 25, 2026
0ed70b1
Rollup merge of #158261 - JonathanBrouwer:may_dangle_target, r=mejrs
jhpratt Jun 25, 2026
21c60a8
Rollup merge of #158358 - raushan728:issues/158158, r=petrochenkov
jhpratt Jun 25, 2026
35f0aa9
Rollup merge of #158392 - aerooneqq:delegation-defaults-in-generics-2…
jhpratt Jun 25, 2026
d109bb0
Rollup merge of #158394 - aerooneqq:mgca-synth-arg-ice, r=petrochenkov
jhpratt Jun 25, 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
88 changes: 87 additions & 1 deletion compiler/rustc_abi/src/layout/ty.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use std::fmt;
use std::ops::Deref;
use std::ops::{Deref, Range};

use rustc_data_structures::intern::Interned;
use rustc_data_structures::range_set::RangeSet;
use rustc_macros::StableHash;

use crate::layout::{FieldIdx, VariantIdx};
Expand Down Expand Up @@ -282,4 +283,89 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
}
found
}

/// The ranges of bytes that are always ignored by the representation relation of this type.
///
/// In other words, for any sequence of bytes, if we reset the these padding bytes to uninit,
/// then these two sequences of bytes represent the same value (or they are both invalid).
/// This is the "guaranteed" padding. There may be more bytes that are padding for some
/// but not all variants of this type; those are not included.
/// (E.g. `Option<i8>` has no guaranteed padding so the empty range set is returned, but its `None` value still has padding).
pub fn padding_ranges<C>(&self, cx: &C) -> Vec<Range<Size>>
where
Ty: TyAbiInterface<'a, C> + Copy,
{
let mut data = RangeSet::new();
self.add_data_ranges(cx, Size::ZERO, &mut data);

// Find gaps between the data ranges.
let mut uninit_ranges = Vec::new();
let mut covered_until = Size::ZERO;
for &(offset, size) in data.0.iter() {
if offset > covered_until {
uninit_ranges.push(covered_until..offset);
}
covered_until = Ord::max(covered_until, offset + size);
}

// Add trailing padding.
if self.size > covered_until {
uninit_ranges.push(covered_until..self.size);
}

uninit_ranges
}

/// Extend `out` with all ranges of bytes that *may* carry relevant data for values of this type.
/// For enums and unions there are offsets that are initialized for some
/// variants but not for others; those offset *will* get added to `out`.
fn add_data_ranges<C>(self, cx: &C, base_offset: Size, out: &mut RangeSet<Size>)
where
Ty: TyAbiInterface<'a, C> + Copy,
{
if self.is_zst() {
return;
}

match &self.variants {
Variants::Empty => { /* done */ }
Variants::Single { index: _ } => match &self.fields {
FieldsShape::Primitive => {
out.add_range(base_offset, self.size);
}
&FieldsShape::Union(field_count) => {
for field in 0..field_count.get() {
let field = self.field(cx, field);
field.add_data_ranges(cx, base_offset, out);
}
}
&FieldsShape::Array { stride, count } => {
let elem = self.field(cx, 0);

// For scalars we know there is no padding between the elements,
// so the entire array is a single big data range.
if elem.backend_repr.is_scalar() {
out.add_range(base_offset, elem.size * count);
} else {
// FIXME: this is really inefficient for large arrays.
for idx in 0..count {
elem.add_data_ranges(cx, base_offset + idx * stride, out);
}
}
}
FieldsShape::Arbitrary { offsets, in_memory_order: _ } => {
for (field, &offset) in offsets.iter_enumerated() {
let field = self.field(cx, field.as_usize());
field.add_data_ranges(cx, base_offset + offset, out);
}
}
},
Variants::Multiple { variants, .. } => {
for variant in variants.indices() {
let variant = self.for_variant(cx, variant);
variant.add_data_ranges(cx, base_offset, out);
}
}
}
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,7 @@ impl FromStr for Endian {
}

/// Size of a type in bytes.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, StableHash))]
pub struct Size {
raw: u64,
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_attr_parsing/src/attributes/semantics.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
use rustc_feature::AttributeStability;
use rustc_hir::target::GenericParamKind;

use super::prelude::*;

pub(crate) struct MayDangleParser;
impl NoArgsAttributeParser for MayDangleParser {
const PATH: &[Symbol] = &[sym::may_dangle];
const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(ALL_TARGETS); //FIXME Still checked fully in `check_attr.rs`
const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: false }),
Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }),
Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: false }),
Allow(Target::GenericParam { kind: GenericParamKind::Lifetime, has_default: true }),
]);
const STABILITY: AttributeStability = unstable!(dropck_eyepatch);
const CREATE: fn(span: Span) -> AttributeKind = AttributeKind::MayDangle;
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/src/target_checking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ pub(crate) fn allowed_targets_applied(

// ensure a consistent order
target_strings.sort();
target_strings.dedup();

// If there is now only 1 target left, show that as the only possible target
let only_target = target_strings.len() == 1;
Expand Down
40 changes: 25 additions & 15 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use rustc_middle::middle::codegen_fn_attrs::{
TargetFeature,
};
use rustc_middle::ty::{self, Instance, TyCtxt};
use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
use rustc_session::config::{
BranchProtection, FunctionReturn, InstrumentMcount, OptLevel, PAuthKey, PacRet,
};
use rustc_span::sym;
use rustc_symbol_mangling::mangle_internal_symbol;
use rustc_target::spec::{Arch, FramePointer, SanitizerSet, StackProbeType, StackProtector};
Expand Down Expand Up @@ -177,7 +179,7 @@ pub(crate) fn frame_pointer(sess: &Session) -> FramePointer {
let opts = &sess.opts;
// "mcount" function relies on stack pointer.
// See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.
if opts.unstable_opts.instrument_mcount {
if opts.unstable_opts.instrument_mcount == InstrumentMcount::Mcount {
fp.ratchet(FramePointer::Always);
}
fp.ratchet(opts.cg.force_frame_pointers);
Expand Down Expand Up @@ -214,7 +216,7 @@ fn instrument_function_attr<'ll>(
instrument_fn: InstrumentFnAttr,
) -> SmallVec<[&'ll Attribute; 4]> {
let mut attrs = SmallVec::new();
if sess.opts.unstable_opts.instrument_mcount {
if sess.opts.unstable_opts.instrument_mcount != InstrumentMcount::Disabled {
// Similar to `clang -pg` behavior. Handled by the
// `post-inline-ee-instrument` LLVM pass.

Expand All @@ -224,18 +226,26 @@ fn instrument_function_attr<'ll>(
};

if instrument_entry {
// The function name varies on platforms.
// See test/CodeGen/mcount.c in clang.
let mcount_name = match &sess.target.llvm_mcount_intrinsic {
Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
None => sess.target.mcount.as_ref(),
};

attrs.push(llvm::CreateAttrStringValue(
cx.llcx,
"instrument-function-entry-inlined",
mcount_name,
));
match sess.opts.unstable_opts.instrument_mcount {
InstrumentMcount::Mcount => {
// The function name varies on platforms.
// See test/CodeGen/mcount.c in clang.
let mcount_name = match &sess.target.llvm_mcount_intrinsic {
Some(llvm_mcount_intrinsic) => llvm_mcount_intrinsic.as_ref(),
None => sess.target.mcount.as_ref(),
};

attrs.push(llvm::CreateAttrStringValue(
cx.llcx,
"instrument-function-entry-inlined",
mcount_name,
));
}
InstrumentMcount::Fentry => {
attrs.push(llvm::CreateAttrStringValue(cx.llcx, "fentry-call", "true"));
}
InstrumentMcount::Disabled => {}
}
}
}
if let Some(options) = &sess.opts.unstable_opts.instrument_xray {
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_codegen_llvm/src/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,17 @@ fn call_simple_intrinsic<'ll, 'tcx>(
sym::fmuladdf64 => ("llvm.fmuladd", &[bx.type_f64()]),
sym::fmuladdf128 => ("llvm.fmuladd", &[bx.type_f128()]),

sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]),
sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]),
// FIXME: LLVM currently mis-compile those intrinsics, re-enable them
// when llvm/llvm-project#{139380,139381,140445} are fixed.
//sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]),
//sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]),
//sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]),
//sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]),
//
sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]),
sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]),
// FIXME: LLVM currently mis-compile those intrinsics, re-enable them
// when llvm/llvm-project#{139380,139381,140445} are fixed.
//sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]),
//sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]),
//sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]),
//sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]),
//
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_session::config::{
self, CFGuard, CrateType, DebugInfo, LinkerFeaturesCli, OutFileName, OutputFilenames,
OutputType, PrintKind, SplitDwarfKind, Strip,
self, CFGuard, CrateType, DebugInfo, InstrumentMcount, LinkerFeaturesCli, OutFileName,
OutputFilenames, OutputType, PrintKind, SplitDwarfKind, Strip,
};
use rustc_session::lint::builtin::LINKER_MESSAGES;
use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
Expand Down Expand Up @@ -2882,7 +2882,7 @@ fn add_order_independent_options(
cmd.pgo_gen();
}

if sess.opts.unstable_opts.instrument_mcount {
if sess.opts.unstable_opts.instrument_mcount != InstrumentMcount::Disabled {
cmd.enable_profiling();
}

Expand Down
73 changes: 71 additions & 2 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::cmp;
use std::ops::Range;

use rustc_abi::{Align, BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
use rustc_abi::{
Align, ArmCall, BackendRepr, CanonAbi, ExternAbi, HasDataLayout, Reg, Size, WrappingRange,
};
use rustc_ast as ast;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_data_structures::packed::Pu128;
Expand Down Expand Up @@ -597,6 +600,20 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"),
};

if self.fn_abi.conv == CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) {
// The return value of an `extern "cmse-nonsecure-entry"` function crosses the
// secure boundary. Zero padding bytes so information does not leak.
//
// This only zeroes "guaranteed" padding. There may be more bytes that are
// padding for some but not all variants of this type; those are not zeroed.
//
// Returning a value with value-dependent padding will instead trigger a lint.
let ret_layout = self.fn_abi.ret.layout;
let uninit_ranges = ret_layout.padding_ranges(bx.cx());
self.zero_byte_ranges(bx, llslot, ret_layout.size, &uninit_ranges);
}

load_cast(bx, cast_ty, llslot, self.fn_abi.ret.layout.align.abi)
}
};
Expand Down Expand Up @@ -1341,6 +1358,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {

self.codegen_argument(
bx,
fn_abi.conv,
op,
by_move,
&mut llargs,
Expand All @@ -1351,6 +1369,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let num_untupled = untuple.map(|tup| {
self.codegen_arguments_untupled(
bx,
fn_abi.conv,
&tup.node,
&mut llargs,
&fn_abi.args[first_args.len()..],
Expand Down Expand Up @@ -1380,6 +1399,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let last_arg = fn_abi.args.last().unwrap();
self.codegen_argument(
bx,
fn_abi.conv,
location,
/* by_move */ false,
&mut llargs,
Expand Down Expand Up @@ -1696,9 +1716,31 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}

fn zero_byte_ranges(
&mut self,
bx: &mut Bx,
ptr: Bx::Value,
limit: Size,
ranges: &[Range<Size>],
) {
let zero = bx.const_u8(0);

for range in ranges {
let end = cmp::min(range.end, limit);
if range.start >= end {
continue;
}
let offset = bx.const_usize(range.start.bytes());
let len = bx.const_usize((end - range.start).bytes());
let ptr = bx.inbounds_ptradd(ptr, offset);
bx.memset(ptr, zero, len, Align::ONE, MemFlags::empty());
}
}

fn codegen_argument(
&mut self,
bx: &mut Bx,
conv: CanonAbi,
op: OperandRef<'tcx, Bx::Value>,
by_move: bool,
llargs: &mut Vec<Bx::Value>,
Expand Down Expand Up @@ -1822,6 +1864,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
MemFlags::empty(),
None,
);

// The arguments of an `extern "cmse-nonsecure-call"` function cross the secure
// boundary. Zero padding bytes so information does not leak.
//
// This only zeroes "guaranteed" padding. There may be more bytes that are
// padding for some but not all variants of this type; those are not zeroed.
//
// Passing an argument with value-dependent padding will instead trigger a lint.
if conv == CanonAbi::Arm(ArmCall::CCmseNonSecureCall) {
self.zero_byte_ranges(
bx,
llscratch,
Size::from_bytes(copy_bytes),
&arg.layout.padding_ranges(bx.cx()),
);
}

// ...and then load it with the ABI type.
llval = load_cast(bx, cast, llscratch, scratch_align);
bx.lifetime_end(llscratch, scratch_size);
Expand All @@ -1848,6 +1907,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn codegen_arguments_untupled(
&mut self,
bx: &mut Bx,
conv: CanonAbi,
operand: &mir::Operand<'tcx>,
llargs: &mut Vec<Bx::Value>,
args: &[ArgAbi<'tcx, Ty<'tcx>>],
Expand All @@ -1867,6 +1927,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let field = bx.load_operand(field_ptr);
self.codegen_argument(
bx,
conv,
field,
by_move,
llargs,
Expand All @@ -1878,7 +1939,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// If the tuple is immediate, the elements are as well.
for i in 0..tuple.layout.fields.count() {
let op = tuple.extract_field(self, bx, i);
self.codegen_argument(bx, op, by_move, llargs, &args[i], lifetime_ends_after_call);
self.codegen_argument(
bx,
conv,
op,
by_move,
llargs,
&args[i],
lifetime_ends_after_call,
);
}
}
tuple.layout.fields.count()
Expand Down
Loading
Loading