Auto merge of #150089 - JonathanBrouwer:rollup-9nmxze1, r=JonathanBrouwer
Rollup of 3 pull requests Successful merges: - rust-lang/rust#150008 (Implement va_arg for Hexagon targets) - rust-lang/rust#150044 (Avoid unhelpful suggestion when crate name is invalid) - rust-lang/rust#150086 (Port `#[rustc_never_returns_null_ptr]` to attribute parser) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
68f11a11b6
11 changed files with 159 additions and 15 deletions
|
|
@ -13,6 +13,21 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
|
|||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcNeverReturnsNullPointerParser;
|
||||
|
||||
impl<S: Stage> NoArgsAttributeParser<S> for RustcNeverReturnsNullPointerParser {
|
||||
const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr];
|
||||
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
|
||||
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
|
||||
Allow(Target::Fn),
|
||||
Allow(Target::Method(MethodKind::Inherent)),
|
||||
Allow(Target::Method(MethodKind::Trait { body: false })),
|
||||
Allow(Target::Method(MethodKind::Trait { body: true })),
|
||||
Allow(Target::Method(MethodKind::TraitImpl)),
|
||||
]);
|
||||
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNeverReturnsNullPointer;
|
||||
}
|
||||
|
||||
pub(crate) struct RustcLayoutScalarValidRangeStartParser;
|
||||
|
||||
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStartParser {
|
||||
|
|
|
|||
|
|
@ -61,8 +61,9 @@ use crate::attributes::prototype::CustomMirParser;
|
|||
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
|
||||
use crate::attributes::rustc_internal::{
|
||||
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser,
|
||||
RustcLegacyConstGenericsParser, RustcMainParser, RustcObjectLifetimeDefaultParser,
|
||||
RustcScalableVectorParser, RustcSimdMonomorphizeLaneLimitParser,
|
||||
RustcLegacyConstGenericsParser, RustcMainParser, RustcNeverReturnsNullPointerParser,
|
||||
RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
|
||||
RustcSimdMonomorphizeLaneLimitParser,
|
||||
};
|
||||
use crate::attributes::semantics::MayDangleParser;
|
||||
use crate::attributes::stability::{
|
||||
|
|
@ -255,6 +256,7 @@ attribute_parsers!(
|
|||
Single<WithoutArgs<PubTransparentParser>>,
|
||||
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
|
||||
Single<WithoutArgs<RustcMainParser>>,
|
||||
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
|
||||
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
|
||||
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
|
||||
Single<WithoutArgs<SpecializationTraitParser>>,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use rustc_codegen_ssa::traits::{
|
|||
};
|
||||
use rustc_middle::ty::Ty;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||
use rustc_target::spec::{Abi, Arch};
|
||||
use rustc_target::spec::{Abi, Arch, Env};
|
||||
|
||||
use crate::builder::Builder;
|
||||
use crate::llvm::{Type, Value};
|
||||
|
|
@ -782,6 +782,129 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>(
|
|||
mem_addr
|
||||
}
|
||||
|
||||
fn emit_hexagon_va_arg_musl<'ll, 'tcx>(
|
||||
bx: &mut Builder<'_, 'll, 'tcx>,
|
||||
list: OperandRef<'tcx, &'ll Value>,
|
||||
target_ty: Ty<'tcx>,
|
||||
) -> &'ll Value {
|
||||
// Implementation of va_arg for Hexagon musl target.
|
||||
// Based on LLVM's HexagonBuiltinVaList implementation.
|
||||
//
|
||||
// struct __va_list_tag {
|
||||
// void *__current_saved_reg_area_pointer;
|
||||
// void *__saved_reg_area_end_pointer;
|
||||
// void *__overflow_area_pointer;
|
||||
// };
|
||||
//
|
||||
// All variadic arguments are passed on the stack, but the musl implementation
|
||||
// uses a register save area for compatibility.
|
||||
let va_list_addr = list.immediate();
|
||||
let layout = bx.cx.layout_of(target_ty);
|
||||
let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi;
|
||||
let ptr_size = bx.tcx().data_layout.pointer_size().bytes();
|
||||
|
||||
// Check if argument fits in register save area
|
||||
let maybe_reg = bx.append_sibling_block("va_arg.maybe_reg");
|
||||
let from_overflow = bx.append_sibling_block("va_arg.from_overflow");
|
||||
let end = bx.append_sibling_block("va_arg.end");
|
||||
|
||||
// Load the three pointers from va_list
|
||||
let current_ptr_addr = va_list_addr;
|
||||
let end_ptr_addr = bx.inbounds_ptradd(va_list_addr, bx.const_usize(ptr_size));
|
||||
let overflow_ptr_addr = bx.inbounds_ptradd(va_list_addr, bx.const_usize(2 * ptr_size));
|
||||
|
||||
let current_ptr = bx.load(bx.type_ptr(), current_ptr_addr, ptr_align_abi);
|
||||
let end_ptr = bx.load(bx.type_ptr(), end_ptr_addr, ptr_align_abi);
|
||||
let overflow_ptr = bx.load(bx.type_ptr(), overflow_ptr_addr, ptr_align_abi);
|
||||
|
||||
// Align current pointer based on argument type size (following LLVM's implementation)
|
||||
// Arguments <= 32 bits (4 bytes) use 4-byte alignment, > 32 bits use 8-byte alignment
|
||||
let type_size_bits = bx.cx.size_of(target_ty).bits();
|
||||
let arg_align = if type_size_bits > 32 {
|
||||
Align::from_bytes(8).unwrap()
|
||||
} else {
|
||||
Align::from_bytes(4).unwrap()
|
||||
};
|
||||
let aligned_current = round_pointer_up_to_alignment(bx, current_ptr, arg_align, bx.type_ptr());
|
||||
|
||||
// Calculate next pointer position (following LLVM's logic)
|
||||
// Arguments <= 32 bits take 4 bytes, > 32 bits take 8 bytes
|
||||
let arg_size = if type_size_bits > 32 { 8 } else { 4 };
|
||||
let next_ptr = bx.inbounds_ptradd(aligned_current, bx.const_usize(arg_size));
|
||||
|
||||
// Check if argument fits in register save area
|
||||
let fits_in_regs = bx.icmp(IntPredicate::IntULE, next_ptr, end_ptr);
|
||||
bx.cond_br(fits_in_regs, maybe_reg, from_overflow);
|
||||
|
||||
// Load from register save area
|
||||
bx.switch_to_block(maybe_reg);
|
||||
let reg_value_addr = aligned_current;
|
||||
// Update current pointer
|
||||
bx.store(next_ptr, current_ptr_addr, ptr_align_abi);
|
||||
bx.br(end);
|
||||
|
||||
// Load from overflow area (stack)
|
||||
bx.switch_to_block(from_overflow);
|
||||
|
||||
// Align overflow pointer using the same alignment rules
|
||||
let aligned_overflow =
|
||||
round_pointer_up_to_alignment(bx, overflow_ptr, arg_align, bx.type_ptr());
|
||||
|
||||
let overflow_value_addr = aligned_overflow;
|
||||
// Update overflow pointer - use the same size calculation
|
||||
let next_overflow = bx.inbounds_ptradd(aligned_overflow, bx.const_usize(arg_size));
|
||||
bx.store(next_overflow, overflow_ptr_addr, ptr_align_abi);
|
||||
|
||||
// IMPORTANT: Also update the current saved register area pointer to match
|
||||
// This synchronizes the pointers when switching to overflow area
|
||||
bx.store(next_overflow, current_ptr_addr, ptr_align_abi);
|
||||
bx.br(end);
|
||||
|
||||
// Return the value
|
||||
bx.switch_to_block(end);
|
||||
let value_addr =
|
||||
bx.phi(bx.type_ptr(), &[reg_value_addr, overflow_value_addr], &[maybe_reg, from_overflow]);
|
||||
bx.load(layout.llvm_type(bx), value_addr, layout.align.abi)
|
||||
}
|
||||
|
||||
fn emit_hexagon_va_arg_bare_metal<'ll, 'tcx>(
|
||||
bx: &mut Builder<'_, 'll, 'tcx>,
|
||||
list: OperandRef<'tcx, &'ll Value>,
|
||||
target_ty: Ty<'tcx>,
|
||||
) -> &'ll Value {
|
||||
// Implementation of va_arg for Hexagon bare-metal (non-musl) targets.
|
||||
// Based on LLVM's EmitVAArgForHexagon implementation.
|
||||
//
|
||||
// va_list is a simple pointer (char *)
|
||||
let va_list_addr = list.immediate();
|
||||
let layout = bx.cx.layout_of(target_ty);
|
||||
let ptr_align_abi = bx.tcx().data_layout.pointer_align().abi;
|
||||
|
||||
// Load current pointer from va_list
|
||||
let current_ptr = bx.load(bx.type_ptr(), va_list_addr, ptr_align_abi);
|
||||
|
||||
// Handle address alignment for types with alignment > 4 bytes
|
||||
let ty_align = layout.align.abi;
|
||||
let aligned_ptr = if ty_align.bytes() > 4 {
|
||||
// Ensure alignment is a power of 2
|
||||
debug_assert!(ty_align.bytes().is_power_of_two(), "Alignment is not power of 2!");
|
||||
round_pointer_up_to_alignment(bx, current_ptr, ty_align, bx.type_ptr())
|
||||
} else {
|
||||
current_ptr
|
||||
};
|
||||
|
||||
// Calculate offset: round up type size to 4-byte boundary (minimum stack slot size)
|
||||
let type_size = layout.size.bytes();
|
||||
let offset = type_size.next_multiple_of(4); // align to 4 bytes
|
||||
|
||||
// Update va_list to point to next argument
|
||||
let next_ptr = bx.inbounds_ptradd(aligned_ptr, bx.const_usize(offset));
|
||||
bx.store(next_ptr, va_list_addr, ptr_align_abi);
|
||||
|
||||
// Load and return the argument value
|
||||
bx.load(layout.llvm_type(bx), aligned_ptr, layout.align.abi)
|
||||
}
|
||||
|
||||
fn emit_xtensa_va_arg<'ll, 'tcx>(
|
||||
bx: &mut Builder<'_, 'll, 'tcx>,
|
||||
list: OperandRef<'tcx, &'ll Value>,
|
||||
|
|
@ -966,6 +1089,13 @@ pub(super) fn emit_va_arg<'ll, 'tcx>(
|
|||
// This includes `target.is_like_darwin`, which on x86_64 targets is like sysv64.
|
||||
Arch::X86_64 => emit_x86_64_sysv64_va_arg(bx, addr, target_ty),
|
||||
Arch::Xtensa => emit_xtensa_va_arg(bx, addr, target_ty),
|
||||
Arch::Hexagon => {
|
||||
if target.env == Env::Musl {
|
||||
emit_hexagon_va_arg_musl(bx, addr, target_ty)
|
||||
} else {
|
||||
emit_hexagon_va_arg_bare_metal(bx, addr, target_ty)
|
||||
}
|
||||
}
|
||||
// For all other architecture/OS combinations fall back to using
|
||||
// the LLVM va_arg instruction.
|
||||
// https://llvm.org/docs/LangRef.html#va-arg-instruction
|
||||
|
|
|
|||
|
|
@ -878,6 +878,9 @@ pub enum AttributeKind {
|
|||
/// Represents `#[rustc_main]`.
|
||||
RustcMain,
|
||||
|
||||
/// Represents `#[rustc_never_returns_null_ptr]`
|
||||
RustcNeverReturnsNullPointer,
|
||||
|
||||
/// Represents `#[rustc_object_lifetime_default]`.
|
||||
RustcObjectLifetimeDefault,
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ impl AttributeKind {
|
|||
RustcLayoutScalarValidRangeStart(..) => Yes,
|
||||
RustcLegacyConstGenerics { .. } => Yes,
|
||||
RustcMain => No,
|
||||
RustcNeverReturnsNullPointer => Yes,
|
||||
RustcObjectLifetimeDefault => No,
|
||||
RustcPassIndirectlyInNonRusticAbis(..) => No,
|
||||
RustcScalableVector { .. } => Yes,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use rustc_ast::LitKind;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind};
|
||||
use rustc_hir::attrs::AttributeKind;
|
||||
use rustc_hir::{BinOpKind, Expr, ExprKind, TyKind, find_attr};
|
||||
use rustc_middle::ty::RawPtr;
|
||||
use rustc_session::{declare_lint, declare_lint_pass};
|
||||
use rustc_span::{Span, sym};
|
||||
|
|
@ -72,14 +73,14 @@ fn useless_check<'a, 'tcx: 'a>(
|
|||
e = e.peel_blocks();
|
||||
if let ExprKind::MethodCall(_, _expr, [], _) = e.kind
|
||||
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
|
||||
&& cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
|
||||
&& find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::RustcNeverReturnsNullPointer)
|
||||
&& let Some(fn_name) = cx.tcx.opt_item_ident(def_id)
|
||||
{
|
||||
return Some(UselessPtrNullChecksDiag::FnRet { fn_name });
|
||||
} else if let ExprKind::Call(path, _args) = e.kind
|
||||
&& let ExprKind::Path(ref qpath) = path.kind
|
||||
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
|
||||
&& cx.tcx.has_attr(def_id, sym::rustc_never_returns_null_ptr)
|
||||
&& find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::RustcNeverReturnsNullPointer)
|
||||
&& let Some(fn_name) = cx.tcx.opt_item_ident(def_id)
|
||||
{
|
||||
return Some(UselessPtrNullChecksDiag::FnRet { fn_name });
|
||||
|
|
|
|||
|
|
@ -257,6 +257,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
| AttributeKind::NoLink
|
||||
| AttributeKind::RustcLayoutScalarValidRangeStart(..)
|
||||
| AttributeKind::RustcLayoutScalarValidRangeEnd(..)
|
||||
| AttributeKind::RustcNeverReturnsNullPointer
|
||||
| AttributeKind::RustcScalableVector { .. }
|
||||
| AttributeKind::RustcSimdMonomorphizeLaneLimit(..)
|
||||
| AttributeKind::RustcShouldNotBeCalledOnConstItems(..)
|
||||
|
|
@ -307,9 +308,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
[sym::rustc_no_implicit_autorefs, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||
}
|
||||
[sym::rustc_never_returns_null_ptr, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||
}
|
||||
[sym::rustc_lint_query_instability, ..] => {
|
||||
self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ session_int_literal_too_large = integer literal is too large
|
|||
.note = value exceeds limit of `{$limit}`
|
||||
|
||||
session_invalid_character_in_crate_name = invalid character {$character} in crate name: `{$crate_name}`
|
||||
.help = you can either pass `--crate-name` on the command line or add `#![crate_name = "…"]` to set the crate name
|
||||
|
||||
session_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
|
||||
.label = invalid suffix `{$suffix}`
|
||||
|
|
|
|||
|
|
@ -238,8 +238,6 @@ pub(crate) struct InvalidCharacterInCrateName {
|
|||
pub(crate) span: Option<Span>,
|
||||
pub(crate) character: char,
|
||||
pub(crate) crate_name: Symbol,
|
||||
#[help]
|
||||
pub(crate) help: Option<()>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ pub fn validate_crate_name(sess: &Session, crate_name: Symbol, span: Option<Span
|
|||
span,
|
||||
character: c,
|
||||
crate_name,
|
||||
help: span.is_none().then_some(()),
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
error: invalid character '$' in crate name: `need_crate_arg_ignore_tidy$x`
|
||||
|
|
||||
= help: you can either pass `--crate-name` on the command line or add `#![crate_name = "…"]` to set the crate name
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue