Auto merge of #147692 - matthiaskrgr:rollup-bqhlwyw, r=matthiaskrgr

Rollup of 12 pull requests

Successful merges:

 - rust-lang/rust#146187 (Unstably constify `ptr::drop_in_place` and related methods)
 - rust-lang/rust#146503 (std: improve handling of timed condition variable waits on macOS)
 - rust-lang/rust#147526 (Move computation of allocator shim contents to cg_ssa)
 - rust-lang/rust#147630 (Bitset cleanups)
 - rust-lang/rust#147638 (bpf: return results larger than one register indirectly)
 - rust-lang/rust#147666 (Replace manual implementation with `carrying_mul_add`)
 - rust-lang/rust#147669 (fix missing link to `std::char` in `std` docs)
 - rust-lang/rust#147673 (pretty print u128 with display)
 - rust-lang/rust#147677 (Fewer exceptions in `span()` on parsed attributes)
 - rust-lang/rust#147680 (Fix ICE caused by associated_item_def_ids on wrong type in resolve diag)
 - rust-lang/rust#147682 (convert `rustc_main` to the new attribute parsing infrastructure)
 - rust-lang/rust#147683 (only check duplicates on old/unparsed attributes)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2025-10-14 20:56:53 +00:00
commit 235a4c083e
63 changed files with 716 additions and 545 deletions

View file

@ -1,7 +1,5 @@
use rustc_span::{Symbol, sym};
use crate::attr::{self, AttributeExt};
#[derive(Debug)]
pub enum EntryPointType {
/// This function is not an entrypoint.
@ -30,11 +28,11 @@ pub enum EntryPointType {
}
pub fn entry_point_type(
attrs: &[impl AttributeExt],
has_rustc_main: bool,
at_root: bool,
name: Option<Symbol>,
) -> EntryPointType {
if attr::contains_name(attrs, sym::rustc_main) {
if has_rustc_main {
EntryPointType::RustcMainAttr
} else if let Some(name) = name
&& name == sym::main

View file

@ -3,7 +3,9 @@ use rustc_span::{Symbol, sym};
#[derive(Clone, Debug, Copy, Eq, PartialEq, HashStable_Generic)]
pub enum AllocatorKind {
/// Use `#[global_allocator]` as global allocator.
Global,
/// Use the default implementation in libstd as global allocator.
Default,
}
@ -15,23 +17,22 @@ pub fn default_fn_name(base: Symbol) -> String {
format!("__rdl_{base}")
}
pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'static str {
match alloc_error_handler_kind {
AllocatorKind::Global => "__rg_oom",
AllocatorKind::Default => "__rdl_oom",
}
}
pub const ALLOC_ERROR_HANDLER: Symbol = sym::alloc_error_handler;
pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable_v2";
/// Argument or return type for methods in the allocator shim
#[derive(Copy, Clone)]
pub enum AllocatorTy {
Layout,
Never,
Ptr,
ResultPtr,
Unit,
Usize,
}
/// A method that will be codegened in the allocator shim.
#[derive(Copy, Clone)]
pub struct AllocatorMethod {
pub name: Symbol,
pub inputs: &'static [AllocatorMethodInput],

View file

@ -1,9 +1,18 @@
use super::prelude::*;
use super::util::parse_single_integer;
pub(crate) struct RustcLayoutScalarValidRangeStart;
pub(crate) struct RustcMainParser;
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart {
impl<S: Stage> NoArgsAttributeParser<S> for RustcMainParser {
const PATH: &'static [Symbol] = &[sym::rustc_main];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;
}
pub(crate) struct RustcLayoutScalarValidRangeStartParser;
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStartParser {
const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
@ -16,9 +25,9 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart {
}
}
pub(crate) struct RustcLayoutScalarValidRangeEnd;
pub(crate) struct RustcLayoutScalarValidRangeEndParser;
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEnd {
impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEndParser {
const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;

View file

@ -53,7 +53,7 @@ use crate::attributes::proc_macro_attrs::{
use crate::attributes::prototype::CustomMirParser;
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
use crate::attributes::rustc_internal::{
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser, RustcMainParser,
RustcObjectLifetimeDefaultParser, RustcSimdMonomorphizeLaneLimitParser,
};
use crate::attributes::semantics::MayDangleParser;
@ -197,8 +197,8 @@ attribute_parsers!(
Single<RecursionLimitParser>,
Single<RustcBuiltinMacroParser>,
Single<RustcForceInlineParser>,
Single<RustcLayoutScalarValidRangeEnd>,
Single<RustcLayoutScalarValidRangeStart>,
Single<RustcLayoutScalarValidRangeEndParser>,
Single<RustcLayoutScalarValidRangeStartParser>,
Single<RustcObjectLifetimeDefaultParser>,
Single<RustcSimdMonomorphizeLaneLimitParser>,
Single<SanitizeParser>,
@ -238,6 +238,7 @@ attribute_parsers!(
Single<WithoutArgs<ProcMacroParser>>,
Single<WithoutArgs<PubTransparentParser>>,
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
Single<WithoutArgs<RustcMainParser>>,
Single<WithoutArgs<SpecializationTraitParser>>,
Single<WithoutArgs<StdInternalSymbolParser>>,
Single<WithoutArgs<TrackCallerParser>>,

View file

@ -1,3 +1,4 @@
use rustc_ast::expand::allocator::{ALLOC_ERROR_HANDLER, global_fn_name};
use rustc_ast::{
self as ast, Fn, FnHeader, FnSig, Generics, ItemKind, Safety, Stmt, StmtKind, TyKind,
};
@ -55,7 +56,7 @@ pub(crate) fn expand(
}
// #[rustc_std_internal_symbol]
// unsafe fn __rg_oom(size: usize, align: usize) -> ! {
// unsafe fn __rust_alloc_error_handler(size: usize, align: usize) -> ! {
// handler(core::alloc::Layout::from_size_align_unchecked(size, align))
// }
fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt {
@ -84,7 +85,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
let kind = ItemKind::Fn(Box::new(Fn {
defaultness: ast::Defaultness::Final,
sig,
ident: Ident::from_str_and_span("__rg_oom", span),
ident: Ident::from_str_and_span(&global_fn_name(ALLOC_ERROR_HANDLER), span),
generics: Generics::default(),
contract: None,
body,

View file

@ -151,7 +151,7 @@ impl AllocFnFactory<'_, '_> {
self.cx.expr_ident(self.span, ident)
}
AllocatorTy::ResultPtr | AllocatorTy::Unit => {
AllocatorTy::Never | AllocatorTy::ResultPtr | AllocatorTy::Unit => {
panic!("can't convert AllocatorTy to an argument")
}
}
@ -163,7 +163,7 @@ impl AllocFnFactory<'_, '_> {
AllocatorTy::Unit => self.cx.ty(self.span, TyKind::Tup(ThinVec::new())),
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
AllocatorTy::Layout | AllocatorTy::Never | AllocatorTy::Usize | AllocatorTy::Ptr => {
panic!("can't convert `AllocatorTy` to an output")
}
}

View file

@ -3,6 +3,7 @@
use std::mem;
use rustc_ast as ast;
use rustc_ast::attr::contains_name;
use rustc_ast::entry::EntryPointType;
use rustc_ast::mut_visit::*;
use rustc_ast::visit::Visitor;
@ -172,9 +173,11 @@ impl<'a> Visitor<'a> for InnerItemLinter<'_> {
fn entry_point_type(item: &ast::Item, at_root: bool) -> EntryPointType {
match &item.kind {
ast::ItemKind::Fn(fn_) => {
rustc_ast::entry::entry_point_type(&item.attrs, at_root, Some(fn_.ident.name))
}
ast::ItemKind::Fn(fn_) => rustc_ast::entry::entry_point_type(
contains_name(&item.attrs, sym::rustc_main),
at_root,
Some(fn_.ident.name),
),
_ => EntryPointType::None,
}
}

View file

@ -3,10 +3,9 @@
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use rustc_ast::expand::allocator::{
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
alloc_error_handler_name, default_fn_name, global_fn_name,
AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name,
};
use rustc_codegen_ssa::base::allocator_kind_for_codegen;
use rustc_codegen_ssa::base::{allocator_kind_for_codegen, allocator_shim_contents};
use rustc_session::config::OomStrategy;
use rustc_symbol_mangling::mangle_internal_symbol;
@ -15,74 +14,56 @@ use crate::prelude::*;
/// Returns whether an allocator shim was created
pub(crate) fn codegen(tcx: TyCtxt<'_>, module: &mut dyn Module) -> bool {
let Some(kind) = allocator_kind_for_codegen(tcx) else { return false };
codegen_inner(
tcx,
module,
kind,
tcx.alloc_error_handler_kind(()).unwrap(),
tcx.sess.opts.unstable_opts.oom,
);
let methods = allocator_shim_contents(tcx, kind);
codegen_inner(tcx, module, &methods, tcx.sess.opts.unstable_opts.oom);
true
}
fn codegen_inner(
tcx: TyCtxt<'_>,
module: &mut dyn Module,
kind: AllocatorKind,
alloc_error_handler_kind: AllocatorKind,
methods: &[AllocatorMethod],
oom_strategy: OomStrategy,
) {
let usize_ty = module.target_config().pointer_type();
if kind == AllocatorKind::Default {
for method in ALLOCATOR_METHODS {
let mut arg_tys = Vec::with_capacity(method.inputs.len());
for input in method.inputs.iter() {
match input.ty {
AllocatorTy::Layout => {
arg_tys.push(usize_ty); // size
arg_tys.push(usize_ty); // align
}
AllocatorTy::Ptr => arg_tys.push(usize_ty),
AllocatorTy::Usize => arg_tys.push(usize_ty),
for method in methods {
let mut arg_tys = Vec::with_capacity(method.inputs.len());
for input in method.inputs.iter() {
match input.ty {
AllocatorTy::Layout => {
arg_tys.push(usize_ty); // size
arg_tys.push(usize_ty); // align
}
AllocatorTy::Ptr => arg_tys.push(usize_ty),
AllocatorTy::Usize => arg_tys.push(usize_ty),
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
AllocatorTy::Never | AllocatorTy::ResultPtr | AllocatorTy::Unit => {
panic!("invalid allocator arg")
}
}
let output = match method.output {
AllocatorTy::ResultPtr => Some(usize_ty),
AllocatorTy::Unit => None,
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
panic!("invalid allocator output")
}
};
let sig = Signature {
call_conv: module.target_config().default_call_conv,
params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
returns: output.into_iter().map(AbiParam::new).collect(),
};
crate::common::create_wrapper_function(
module,
sig,
&mangle_internal_symbol(tcx, &global_fn_name(method.name)),
&mangle_internal_symbol(tcx, &default_fn_name(method.name)),
);
}
}
let output = match method.output {
AllocatorTy::ResultPtr => Some(usize_ty),
AllocatorTy::Never | AllocatorTy::Unit => None,
let sig = Signature {
call_conv: module.target_config().default_call_conv,
params: vec![AbiParam::new(usize_ty), AbiParam::new(usize_ty)],
returns: vec![],
};
crate::common::create_wrapper_function(
module,
sig,
&mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind)),
);
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
panic!("invalid allocator output")
}
};
let sig = Signature {
call_conv: module.target_config().default_call_conv,
params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
returns: output.into_iter().map(AbiParam::new).collect(),
};
crate::common::create_wrapper_function(
module,
sig,
&mangle_internal_symbol(tcx, &global_fn_name(method.name)),
&mangle_internal_symbol(tcx, &default_fn_name(method.name)),
);
}
{
let sig = Signature {

View file

@ -2,8 +2,7 @@
use gccjit::FnAttribute;
use gccjit::{Context, FunctionType, RValue, ToRValue, Type};
use rustc_ast::expand::allocator::{
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
alloc_error_handler_name, default_fn_name, global_fn_name,
AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name,
};
use rustc_middle::bug;
use rustc_middle::ty::TyCtxt;
@ -18,8 +17,7 @@ pub(crate) unsafe fn codegen(
tcx: TyCtxt<'_>,
mods: &mut GccContext,
_module_name: &str,
kind: AllocatorKind,
alloc_error_handler_kind: AllocatorKind,
methods: &[AllocatorMethod],
) {
let context = &mods.context;
let usize = match tcx.sess.target.pointer_width {
@ -31,45 +29,35 @@ pub(crate) unsafe fn codegen(
let i8 = context.new_type::<i8>();
let i8p = i8.make_pointer();
if kind == AllocatorKind::Default {
for method in ALLOCATOR_METHODS {
let mut types = Vec::with_capacity(method.inputs.len());
for input in method.inputs.iter() {
match input.ty {
AllocatorTy::Layout => {
types.push(usize);
types.push(usize);
}
AllocatorTy::Ptr => types.push(i8p),
AllocatorTy::Usize => types.push(usize),
for method in methods {
let mut types = Vec::with_capacity(method.inputs.len());
for input in method.inputs.iter() {
match input.ty {
AllocatorTy::Layout => {
types.push(usize);
types.push(usize);
}
AllocatorTy::Ptr => types.push(i8p),
AllocatorTy::Usize => types.push(usize),
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
AllocatorTy::Never | AllocatorTy::ResultPtr | AllocatorTy::Unit => {
panic!("invalid allocator arg")
}
}
let output = match method.output {
AllocatorTy::ResultPtr => Some(i8p),
AllocatorTy::Unit => None,
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
panic!("invalid allocator output")
}
};
let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name));
let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name));
create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output);
}
}
let output = match method.output {
AllocatorTy::ResultPtr => Some(i8p),
AllocatorTy::Never | AllocatorTy::Unit => None,
// FIXME(bjorn3): Add noreturn attribute
create_wrapper_function(
tcx,
context,
&mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))),
&[usize, usize],
None,
);
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
panic!("invalid allocator output")
}
};
let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name));
let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name));
create_wrapper_function(tcx, context, &from_name, Some(&to_name), &types, output);
}
create_const_value_function(
tcx,

View file

@ -92,7 +92,7 @@ use back::lto::{ThinBuffer, ThinData};
use gccjit::{CType, Context, OptimizationLevel};
#[cfg(feature = "master")]
use gccjit::{TargetInfo, Version};
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_ast::expand::allocator::AllocatorMethod;
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule};
use rustc_codegen_ssa::back::write::{
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryFn,
@ -284,8 +284,7 @@ impl ExtraBackendMethods for GccCodegenBackend {
&self,
tcx: TyCtxt<'_>,
module_name: &str,
kind: AllocatorKind,
alloc_error_handler_kind: AllocatorKind,
methods: &[AllocatorMethod],
) -> Self::Module {
let mut mods = GccContext {
context: Arc::new(SyncContext::new(new_context(tcx))),
@ -295,7 +294,7 @@ impl ExtraBackendMethods for GccCodegenBackend {
};
unsafe {
allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind);
allocator::codegen(tcx, &mut mods, module_name, methods);
}
mods
}

View file

@ -1,7 +1,6 @@
use libc::c_uint;
use rustc_ast::expand::allocator::{
ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE,
alloc_error_handler_name, default_fn_name, global_fn_name,
AllocatorMethod, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, default_fn_name, global_fn_name,
};
use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _;
use rustc_middle::bug;
@ -21,8 +20,7 @@ pub(crate) unsafe fn codegen(
tcx: TyCtxt<'_>,
cx: SimpleCx<'_>,
module_name: &str,
kind: AllocatorKind,
alloc_error_handler_kind: AllocatorKind,
methods: &[AllocatorMethod],
) {
let usize = match tcx.sess.target.pointer_width {
16 => cx.type_i16(),
@ -33,91 +31,85 @@ pub(crate) unsafe fn codegen(
let i8 = cx.type_i8();
let i8p = cx.type_ptr();
if kind == AllocatorKind::Default {
for method in ALLOCATOR_METHODS {
let mut args = Vec::with_capacity(method.inputs.len());
for input in method.inputs.iter() {
match input.ty {
AllocatorTy::Layout => {
args.push(usize); // size
args.push(usize); // align
}
AllocatorTy::Ptr => args.push(i8p),
AllocatorTy::Usize => args.push(usize),
for method in methods {
let mut args = Vec::with_capacity(method.inputs.len());
for input in method.inputs.iter() {
match input.ty {
AllocatorTy::Layout => {
args.push(usize); // size
args.push(usize); // align
}
AllocatorTy::Ptr => args.push(i8p),
AllocatorTy::Usize => args.push(usize),
AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
AllocatorTy::Never | AllocatorTy::ResultPtr | AllocatorTy::Unit => {
panic!("invalid allocator arg")
}
}
let output = match method.output {
AllocatorTy::ResultPtr => Some(i8p),
AllocatorTy::Unit => None,
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
panic!("invalid allocator output")
}
};
let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name));
let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name));
let alloc_attr_flag = match method.name {
sym::alloc => CodegenFnAttrFlags::ALLOCATOR,
sym::dealloc => CodegenFnAttrFlags::DEALLOCATOR,
sym::realloc => CodegenFnAttrFlags::REALLOCATOR,
sym::alloc_zeroed => CodegenFnAttrFlags::ALLOCATOR_ZEROED,
_ => unreachable!("Unknown allocator method!"),
};
let mut attrs = CodegenFnAttrs::new();
attrs.flags |= alloc_attr_flag;
create_wrapper_function(
tcx,
&cx,
&from_name,
Some(&to_name),
&args,
output,
false,
&attrs,
);
}
}
// rust alloc error handler
create_wrapper_function(
tcx,
&cx,
&mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
Some(&mangle_internal_symbol(tcx, alloc_error_handler_name(alloc_error_handler_kind))),
&[usize, usize], // size, align
None,
true,
&CodegenFnAttrs::new(),
);
let mut no_return = false;
let output = match method.output {
AllocatorTy::ResultPtr => Some(i8p),
AllocatorTy::Unit => None,
AllocatorTy::Never => {
no_return = true;
None
}
unsafe {
// __rust_alloc_error_handler_should_panic_v2
create_const_value_function(
tcx,
&cx,
&mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
&i8,
&llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, FALSE),
);
AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
panic!("invalid allocator output")
}
};
// __rust_no_alloc_shim_is_unstable_v2
let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name));
let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name));
let alloc_attr_flag = match method.name {
sym::alloc => CodegenFnAttrFlags::ALLOCATOR,
sym::dealloc => CodegenFnAttrFlags::DEALLOCATOR,
sym::realloc => CodegenFnAttrFlags::REALLOCATOR,
sym::alloc_zeroed => CodegenFnAttrFlags::ALLOCATOR_ZEROED,
_ => CodegenFnAttrFlags::empty(),
};
let mut attrs = CodegenFnAttrs::new();
attrs.flags |= alloc_attr_flag;
create_wrapper_function(
tcx,
&cx,
&mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
None,
&[],
None,
false,
&CodegenFnAttrs::new(),
&from_name,
Some(&to_name),
&args,
output,
no_return,
&attrs,
);
}
// __rust_alloc_error_handler_should_panic_v2
create_const_value_function(
tcx,
&cx,
&mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
&i8,
unsafe {
llvm::LLVMConstInt(i8, tcx.sess.opts.unstable_opts.oom.should_panic() as u64, FALSE)
},
);
// __rust_no_alloc_shim_is_unstable_v2
create_wrapper_function(
tcx,
&cx,
&mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
None,
&[],
None,
false,
&CodegenFnAttrs::new(),
);
if tcx.sess.opts.debuginfo != DebugInfo::None {
let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod);
debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);

View file

@ -30,7 +30,7 @@ use back::write::{create_informational_target_machine, create_target_machine};
use context::SimpleCx;
use errors::ParseTargetMachineConfig;
use llvm_util::target_config;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_ast::expand::allocator::AllocatorMethod;
use rustc_codegen_ssa::back::lto::{SerializedModule, ThinModule};
use rustc_codegen_ssa::back::write::{
CodegenContext, FatLtoInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
@ -109,14 +109,13 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
&self,
tcx: TyCtxt<'tcx>,
module_name: &str,
kind: AllocatorKind,
alloc_error_handler_kind: AllocatorKind,
methods: &[AllocatorMethod],
) -> ModuleLlvm {
let module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
let cx =
SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size());
unsafe {
allocator::codegen(tcx, cx, module_name, kind, alloc_error_handler_kind);
allocator::codegen(tcx, cx, module_name, methods);
}
module_llvm
}

View file

@ -1,7 +1,9 @@
use std::collections::hash_map::Entry::*;
use rustc_abi::{CanonAbi, X86Call};
use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name};
use rustc_ast::expand::allocator::{
ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name,
};
use rustc_data_structures::unord::UnordMap;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId};
@ -498,7 +500,7 @@ pub(crate) fn allocator_shim_symbols(
.iter()
.map(move |method| mangle_internal_symbol(tcx, global_fn_name(method.name).as_str()))
.chain([
mangle_internal_symbol(tcx, "__rust_alloc_error_handler"),
mangle_internal_symbol(tcx, global_fn_name(ALLOC_ERROR_HANDLER).as_str()),
mangle_internal_symbol(tcx, OomStrategy::SYMBOL),
mangle_internal_symbol(tcx, NO_ALLOC_SHIM_IS_UNSTABLE),
])

View file

@ -6,7 +6,9 @@ use std::time::{Duration, Instant};
use itertools::Itertools;
use rustc_abi::FIRST_VARIANT;
use rustc_ast as ast;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_ast::expand::allocator::{
ALLOC_ERROR_HANDLER, ALLOCATOR_METHODS, AllocatorKind, AllocatorMethod, AllocatorTy,
};
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
use rustc_data_structures::sync::{IntoDynSyncSend, par_map};
@ -655,6 +657,26 @@ pub(crate) fn needs_allocator_shim_for_linking(
!any_dynamic_crate
}
pub fn allocator_shim_contents(tcx: TyCtxt<'_>, kind: AllocatorKind) -> Vec<AllocatorMethod> {
let mut methods = Vec::new();
if kind == AllocatorKind::Default {
methods.extend(ALLOCATOR_METHODS.into_iter().copied());
}
// If the return value of allocator_kind_for_codegen is Some then
// alloc_error_handler_kind must also be Some.
if tcx.alloc_error_handler_kind(()).unwrap() == AllocatorKind::Default {
methods.push(AllocatorMethod {
name: ALLOC_ERROR_HANDLER,
inputs: &[],
output: AllocatorTy::Never,
});
}
methods
}
pub fn codegen_crate<B: ExtraBackendMethods>(
backend: B,
tcx: TyCtxt<'_>,
@ -699,14 +721,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
tcx.sess.time("write_allocator_module", || {
let module = backend.codegen_allocator(
tcx,
&llmod_id,
kind,
// If allocator_kind is Some then alloc_error_handler_kind must
// also be Some.
tcx.alloc_error_handler_kind(()).unwrap(),
);
let module =
backend.codegen_allocator(tcx, &llmod_id, &allocator_shim_contents(tcx, kind));
Some(ModuleCodegen::new_allocator(llmod_id, module))
})
} else {

View file

@ -279,7 +279,7 @@ fn process_builtin_attrs(
AttributeKind::StdInternalSymbol(_) => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL
}
AttributeKind::Linkage(linkage, _) => {
AttributeKind::Linkage(linkage, span) => {
let linkage = Some(*linkage);
if tcx.is_foreign_item(did) {
@ -287,7 +287,7 @@ fn process_builtin_attrs(
if tcx.is_mutable_static(did.into()) {
let mut diag = tcx.dcx().struct_span_err(
attr.span(),
*span,
"extern mutable statics are not allowed with `#[linkage]`",
);
diag.note(

View file

@ -1,7 +1,7 @@
use std::any::Any;
use std::hash::Hash;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_ast::expand::allocator::AllocatorMethod;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_metadata::EncodedMetadata;
@ -116,8 +116,7 @@ pub trait ExtraBackendMethods:
&self,
tcx: TyCtxt<'tcx>,
module_name: &str,
kind: AllocatorKind,
alloc_error_handler_kind: AllocatorKind,
methods: &[AllocatorMethod],
) -> Self::Module;
/// This generates the codegen unit and returns it along with

View file

@ -670,6 +670,9 @@ pub enum AttributeKind {
/// Represents `#[rustc_layout_scalar_valid_range_start]`.
RustcLayoutScalarValidRangeStart(Box<u128>, Span),
/// Represents `#[rustc_main]`.
RustcMain,
/// Represents `#[rustc_object_lifetime_default]`.
RustcObjectLifetimeDefault,

View file

@ -88,6 +88,7 @@ impl AttributeKind {
RustcCoherenceIsCore(..) => No,
RustcLayoutScalarValidRangeEnd(..) => Yes,
RustcLayoutScalarValidRangeStart(..) => Yes,
RustcMain => No,
RustcObjectLifetimeDefault => No,
RustcSimdMonomorphizeLaneLimit(..) => Yes, // Affects layout computation, which needs to work cross-crate
Sanitize { .. } => No,

View file

@ -26,16 +26,6 @@ pub trait PrintAttribute {
fn print_attribute(&self, p: &mut Printer);
}
impl PrintAttribute for u128 {
fn should_render(&self) -> bool {
true
}
fn print_attribute(&self, p: &mut Printer) {
p.word(self.to_string())
}
}
impl<T: PrintAttribute> PrintAttribute for &T {
fn should_render(&self) -> bool {
T::should_render(self)
@ -148,7 +138,7 @@ macro_rules! print_tup {
print_tup!(A B C D E F G H);
print_skip!(Span, (), ErrorGuaranteed);
print_disp!(u16, bool, NonZero<u32>, Limit);
print_disp!(u16, u128, bool, NonZero<u32>, Limit);
print_debug!(
Symbol,
Ident,

View file

@ -1315,8 +1315,6 @@ impl AttributeExt for Attribute {
// FIXME: should not be needed anymore when all attrs are parsed
Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span,
Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span,
Attribute::Parsed(AttributeKind::AllowInternalUnsafe(span)) => *span,
Attribute::Parsed(AttributeKind::Linkage(_, span)) => *span,
a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"),
}
}

View file

@ -160,7 +160,7 @@ impl<T: Idx> DenseBitSet<T> {
/// Count the number of set bits in the set.
pub fn count(&self) -> usize {
self.words.iter().map(|e| e.count_ones() as usize).sum()
count_ones(&self.words)
}
/// Returns `true` if `self` contains `elem`.
@ -786,7 +786,7 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
match (&mut self_chunk, &other_chunk) {
(_, Zeros) | (Ones, _) => {}
(Zeros, Ones) | (Mixed(..), Ones) | (Zeros, Mixed(..)) => {
(Zeros, _) | (Mixed(..), Ones) => {
// `other_chunk` fully overwrites `self_chunk`
*self_chunk = other_chunk.clone();
changed = true;
@ -814,10 +814,8 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
op,
);
debug_assert!(has_changed);
*self_chunk_count = self_chunk_words[0..num_words]
.iter()
.map(|w| w.count_ones() as ChunkSize)
.sum();
*self_chunk_count =
count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_count == chunk_domain_size {
*self_chunk = Ones;
}
@ -850,7 +848,7 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
match (&mut self_chunk, &other_chunk) {
(Zeros, _) | (_, Zeros) => {}
(Ones | Mixed(_, _), Ones) => {
(Ones | Mixed(..), Ones) => {
changed = true;
*self_chunk = Zeros;
}
@ -868,10 +866,7 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
let self_chunk_count = chunk_domain_size - *other_chunk_count;
debug_assert_eq!(
self_chunk_count,
self_chunk_words[0..num_words]
.iter()
.map(|w| w.count_ones() as ChunkSize)
.sum()
count_ones(&self_chunk_words[0..num_words]) as ChunkSize
);
*self_chunk = Mixed(self_chunk_count, Rc::new(self_chunk_words));
}
@ -894,10 +889,8 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
op,
);
debug_assert!(has_changed);
*self_chunk_count = self_chunk_words[0..num_words]
.iter()
.map(|w| w.count_ones() as ChunkSize)
.sum();
*self_chunk_count =
count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_count == 0 {
*self_chunk = Zeros;
}
@ -953,10 +946,8 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
op,
);
debug_assert!(has_changed);
*self_chunk_count = self_chunk_words[0..num_words]
.iter()
.map(|w| w.count_ones() as ChunkSize)
.sum();
*self_chunk_count =
count_ones(&self_chunk_words[0..num_words]) as ChunkSize;
if *self_chunk_count == 0 {
*self_chunk = Zeros;
}
@ -970,48 +961,6 @@ impl<T: Idx> BitRelations<ChunkedBitSet<T>> for ChunkedBitSet<T> {
}
}
impl<T: Idx> BitRelations<ChunkedBitSet<T>> for DenseBitSet<T> {
fn union(&mut self, other: &ChunkedBitSet<T>) -> bool {
sequential_update(|elem| self.insert(elem), other.iter())
}
fn subtract(&mut self, _other: &ChunkedBitSet<T>) -> bool {
unimplemented!("implement if/when necessary");
}
fn intersect(&mut self, other: &ChunkedBitSet<T>) -> bool {
assert_eq!(self.domain_size(), other.domain_size);
let mut changed = false;
for (i, chunk) in other.chunks.iter().enumerate() {
let mut words = &mut self.words[i * CHUNK_WORDS..];
if words.len() > CHUNK_WORDS {
words = &mut words[..CHUNK_WORDS];
}
match chunk {
Zeros => {
for word in words {
if *word != 0 {
changed = true;
*word = 0;
}
}
}
Ones => (),
Mixed(_, data) => {
for (i, word) in words.iter_mut().enumerate() {
let new_val = *word & data[i];
if new_val != *word {
changed = true;
*word = new_val;
}
}
}
}
}
changed
}
}
impl<T> Clone for ChunkedBitSet<T> {
fn clone(&self) -> Self {
ChunkedBitSet {
@ -1085,21 +1034,12 @@ impl Chunk {
assert!(0 < count && count < chunk_domain_size);
// Check the number of set bits matches `count`.
assert_eq!(
words.iter().map(|w| w.count_ones() as ChunkSize).sum::<ChunkSize>(),
count
);
assert_eq!(count_ones(words.as_slice()) as ChunkSize, count);
// Check the not-in-use words are all zeroed.
let num_words = num_words(chunk_domain_size as usize);
if num_words < CHUNK_WORDS {
assert_eq!(
words[num_words..]
.iter()
.map(|w| w.count_ones() as ChunkSize)
.sum::<ChunkSize>(),
0
);
assert_eq!(count_ones(&words[num_words..]) as ChunkSize, 0);
}
}
}
@ -1122,15 +1062,6 @@ enum ChunkIter<'a> {
Finished,
}
// Applies a function to mutate a bitset, and returns true if any
// of the applications return true
fn sequential_update<T: Idx>(
mut self_update: impl FnMut(T) -> bool,
it: impl Iterator<Item = T>,
) -> bool {
it.fold(false, |changed, elem| self_update(elem) | changed)
}
impl<T: Idx> fmt::Debug for ChunkedBitSet<T> {
fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
w.debug_list().entries(self.iter()).finish()
@ -1590,7 +1521,7 @@ impl<R: Idx, C: Idx> BitMatrix<R, C> {
/// Returns the number of elements in `row`.
pub fn count(&self, row: R) -> usize {
let (start, end) = self.range(row);
self.words[start..end].iter().map(|e| e.count_ones() as usize).sum()
count_ones(&self.words[start..end])
}
}
@ -1801,6 +1732,11 @@ fn max_bit(word: Word) -> usize {
WORD_BITS - 1 - word.leading_zeros() as usize
}
#[inline]
fn count_ones(words: &[Word]) -> usize {
words.iter().map(|word| word.count_ones() as usize).sum()
}
/// Integral type used to represent the bit set.
pub trait FiniteBitSetTy:
BitAnd<Output = Self>

View file

@ -306,34 +306,6 @@ fn with_elements_chunked(elements: &[usize], domain_size: usize) -> ChunkedBitSe
s
}
fn with_elements_standard(elements: &[usize], domain_size: usize) -> DenseBitSet<usize> {
let mut s = DenseBitSet::new_empty(domain_size);
for &e in elements {
assert!(s.insert(e));
}
s
}
#[test]
fn chunked_bitset_into_bitset_operations() {
let a = vec![1, 5, 7, 11, 15, 2000, 3000];
let b = vec![3, 4, 11, 3000, 4000];
let aub = vec![1, 3, 4, 5, 7, 11, 15, 2000, 3000, 4000];
let aib = vec![11, 3000];
let b = with_elements_chunked(&b, 9876);
let mut union = with_elements_standard(&a, 9876);
assert!(union.union(&b));
assert!(!union.union(&b));
assert!(union.iter().eq(aub.iter().copied()));
let mut intersection = with_elements_standard(&a, 9876);
assert!(intersection.intersect(&b));
assert!(!intersection.intersect(&b));
assert!(intersection.iter().eq(aib.iter().copied()));
}
#[test]
fn chunked_bitset_iter() {
fn check_iter(bit: &ChunkedBitSet<usize>, vec: &Vec<usize>) {

View file

@ -310,15 +310,17 @@ impl EarlyLintPass for UnsafeCode {
}
ast::ItemKind::MacroDef(..) => {
if let Some(attr) = AttributeParser::parse_limited(
cx.builder.sess(),
&it.attrs,
sym::allow_internal_unsafe,
it.span,
DUMMY_NODE_ID,
Some(cx.builder.features()),
) {
self.report_unsafe(cx, attr.span(), BuiltinUnsafe::AllowInternalUnsafe);
if let Some(hir::Attribute::Parsed(AttributeKind::AllowInternalUnsafe(span))) =
AttributeParser::parse_limited(
cx.builder.sess(),
&it.attrs,
sym::allow_internal_unsafe,
it.span,
DUMMY_NODE_ID,
Some(cx.builder.features()),
)
{
self.report_unsafe(cx, span, BuiltinUnsafe::AllowInternalUnsafe);
}
}

View file

@ -6,7 +6,7 @@ use std::str::FromStr;
use std::time::Duration;
use std::{cmp, env, iter};
use rustc_ast::expand::allocator::{AllocatorKind, alloc_error_handler_name, global_fn_name};
use rustc_ast::expand::allocator::{ALLOC_ERROR_HANDLER, AllocatorKind, global_fn_name};
use rustc_ast::{self as ast, *};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::owned_slice::OwnedSlice;
@ -1087,10 +1087,8 @@ impl CStore {
}
spans => !spans.is_empty(),
};
self.has_alloc_error_handler = match &*fn_spans(
krate,
Symbol::intern(alloc_error_handler_name(AllocatorKind::Global)),
) {
let alloc_error_handler = Symbol::intern(&global_fn_name(ALLOC_ERROR_HANDLER));
self.has_alloc_error_handler = match &*fn_spans(krate, alloc_error_handler) {
[span1, span2, ..] => {
tcx.dcx()
.emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });

View file

@ -34,9 +34,6 @@ passes_attr_crate_level =
.suggestion = to apply to the crate, use an inner attribute
.note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
passes_attr_only_in_functions =
`{$attr}` attribute can only be used on functions
passes_autodiff_attr =
`#[autodiff]` should be applied to a function
.label = not a function

View file

@ -283,6 +283,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
| AttributeKind::ObjcSelector { .. }
| AttributeKind::RustcCoherenceIsCore(..)
| AttributeKind::DebuggerVisualizer(..)
| AttributeKind::RustcMain,
) => { /* do nothing */ }
Attribute::Unparsed(attr_item) => {
style = Some(attr_item.style);
@ -394,8 +395,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
if hir_id != CRATE_HIR_ID {
match attr {
Attribute::Parsed(_) => { /* Already validated. */ }
@ -441,8 +440,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
}
}
if let Some(BuiltinAttribute { duplicates, .. }) = builtin {
check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
if let Attribute::Unparsed(unparsed_attr) = attr
&& let Some(BuiltinAttribute { duplicates, .. }) =
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
{
check_duplicates(
self.tcx,
unparsed_attr.span,
attr,
hir_id,
*duplicates,
&mut seen,
);
}
self.check_unused_attribute(hir_id, attr, style)
@ -2397,14 +2406,8 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
// Check for builtin attributes at the crate level
// which were unsuccessfully resolved due to cannot determine
// resolution for the attribute macro error.
const ATTRS_TO_CHECK: &[Symbol] = &[
sym::rustc_main,
sym::derive,
sym::test,
sym::test_case,
sym::global_allocator,
sym::bench,
];
const ATTRS_TO_CHECK: &[Symbol] =
&[sym::derive, sym::test, sym::test_case, sym::global_allocator, sym::bench];
for attr in attrs {
// FIXME(jdonszelmann): all attrs should be combined here cleaning this up some day.
@ -2483,6 +2486,7 @@ pub(crate) fn provide(providers: &mut Providers) {
// FIXME(jdonszelmann): remove, check during parsing
fn check_duplicates(
tcx: TyCtxt<'_>,
attr_span: Span,
attr: &Attribute,
hir_id: HirId,
duplicates: AttributeDuplicates,
@ -2499,10 +2503,10 @@ fn check_duplicates(
match seen.entry(attr_name) {
Entry::Occupied(mut entry) => {
let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
let to_remove = entry.insert(attr.span());
(to_remove, attr.span())
let to_remove = entry.insert(attr_span);
(to_remove, attr_span)
} else {
(attr.span(), *entry.get())
(attr_span, *entry.get())
};
tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
@ -2519,22 +2523,22 @@ fn check_duplicates(
);
}
Entry::Vacant(entry) => {
entry.insert(attr.span());
entry.insert(attr_span);
}
}
}
ErrorFollowing | ErrorPreceding => match seen.entry(attr_name) {
Entry::Occupied(mut entry) => {
let (this, other) = if matches!(duplicates, ErrorPreceding) {
let to_remove = entry.insert(attr.span());
(to_remove, attr.span())
let to_remove = entry.insert(attr_span);
(to_remove, attr_span)
} else {
(attr.span(), *entry.get())
(attr_span, *entry.get())
};
tcx.dcx().emit_err(errors::UnusedMultiple { this, other, name: attr_name });
}
Entry::Vacant(entry) => {
entry.insert(attr.span());
entry.insert(attr_span);
}
},
}

View file

@ -1,16 +1,16 @@
use rustc_ast::attr;
use rustc_ast::entry::EntryPointType;
use rustc_errors::codes::*;
use rustc_hir::def::DefKind;
use rustc_hir::attrs::AttributeKind;
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::{CRATE_HIR_ID, ItemId, Node};
use rustc_hir::{CRATE_HIR_ID, ItemId, Node, find_attr};
use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::RemapFileNameExt;
use rustc_session::config::{CrateType, EntryFnType, RemapPathScopeComponents, sigpipe};
use rustc_span::{Span, Symbol, sym};
use rustc_span::{Span, sym};
use crate::errors::{AttrOnlyInFunctions, ExternMain, MultipleRustcMain, NoMainErr};
use crate::errors::{ExternMain, MultipleRustcMain, NoMainErr};
struct EntryContext<'tcx> {
tcx: TyCtxt<'tcx>,
@ -44,26 +44,12 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
configure_main(tcx, &ctxt)
}
fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> {
let attrs = ctxt.tcx.hir_attrs(id.hir_id());
attr::find_by_name(attrs, sym).map(|attr| attr.span())
}
fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) {
for attr in [sym::rustc_main] {
if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr });
}
}
return;
}
let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID);
let attrs = ctxt.tcx.hir_attrs(id.hir_id());
let entry_point_type = rustc_ast::entry::entry_point_type(
attrs,
find_attr!(attrs, AttributeKind::RustcMain),
at_root,
ctxt.tcx.opt_item_name(id.owner_id.to_def_id()),
);

View file

@ -843,14 +843,6 @@ pub(crate) struct FeaturePreviouslyDeclared<'a> {
pub prev_declared: &'a str,
}
#[derive(Diagnostic)]
#[diag(passes_attr_only_in_functions)]
pub(crate) struct AttrOnlyInFunctions {
#[primary_span]
pub span: Span,
pub attr: Symbol,
}
#[derive(Diagnostic)]
#[diag(passes_multiple_rustc_main, code = E0137)]
pub(crate) struct MultipleRustcMain {

View file

@ -2332,30 +2332,44 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
fn field_idents(&self, def_id: DefId) -> Option<Vec<Ident>> {
match def_id.as_local() {
Some(def_id) => self.field_names.get(&def_id).cloned(),
None => Some(
self.tcx
.associated_item_def_ids(def_id)
.iter()
.map(|&def_id| {
Ident::new(self.tcx.item_name(def_id), self.tcx.def_span(def_id))
})
.collect(),
),
None if matches!(
self.tcx.def_kind(def_id),
DefKind::Struct | DefKind::Union | DefKind::Variant
) =>
{
Some(
self.tcx
.associated_item_def_ids(def_id)
.iter()
.map(|&def_id| {
Ident::new(self.tcx.item_name(def_id), self.tcx.def_span(def_id))
})
.collect(),
)
}
_ => None,
}
}
fn field_defaults(&self, def_id: DefId) -> Option<Vec<Symbol>> {
match def_id.as_local() {
Some(def_id) => self.field_defaults.get(&def_id).cloned(),
None => Some(
self.tcx
.associated_item_def_ids(def_id)
.iter()
.filter_map(|&def_id| {
self.tcx.default_field(def_id).map(|_| self.tcx.item_name(def_id))
})
.collect(),
),
None if matches!(
self.tcx.def_kind(def_id),
DefKind::Struct | DefKind::Union | DefKind::Variant
) =>
{
Some(
self.tcx
.associated_item_def_ids(def_id)
.iter()
.filter_map(|&def_id| {
self.tcx.default_field(def_id).map(|_| self.tcx.item_name(def_id))
})
.collect(),
)
}
_ => None,
}
}

View file

@ -29,3 +29,9 @@ pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
classify_arg(arg);
}
}
pub(crate) fn compute_rust_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
if !fn_abi.ret.is_ignore() {
classify_ret(&mut fn_abi.ret);
}
}

View file

@ -715,6 +715,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
"riscv32" | "riscv64" => riscv::compute_rust_abi_info(cx, self),
"loongarch32" | "loongarch64" => loongarch::compute_rust_abi_info(cx, self),
"aarch64" => aarch64::compute_rust_abi_info(cx, self),
"bpf" => bpf::compute_rust_abi_info(self),
_ => {}
};

View file

@ -139,9 +139,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.175"
version = "0.2.177"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
dependencies = [
"rustc-std-workspace-core",
]

View file

@ -361,7 +361,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
unsafe extern "Rust" {
// This is the magic symbol to call the global alloc error handler. rustc generates
// it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
// default implementations below (`__rdl_oom`) otherwise.
// default implementations below (`__rdl_alloc_error_handler`) otherwise.
#[rustc_std_internal_symbol]
fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
}
@ -425,7 +425,7 @@ pub mod __alloc_error_handler {
// called via generated `__rust_alloc_error_handler` if there is no
// `#[alloc_error_handler]`.
#[rustc_std_internal_symbol]
pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
pub unsafe fn __rdl_alloc_error_handler(size: usize, _align: usize) -> ! {
unsafe extern "Rust" {
// This symbol is emitted by rustc next to __rust_alloc_error_handler.
// Its value depends on the -Zoom={panic,abort} compiler option.

View file

@ -1,3 +1,4 @@
use crate::marker::Destruct;
use crate::ops::{Deref, DerefMut, DerefPure};
use crate::ptr;
@ -249,7 +250,11 @@ impl<T: ?Sized> ManuallyDrop<T> {
/// [pinned]: crate::pin
#[stable(feature = "manually_drop", since = "1.20.0")]
#[inline]
pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
pub const unsafe fn drop(slot: &mut ManuallyDrop<T>)
where
T: [const] Destruct,
{
// SAFETY: we are dropping the value pointed to by a mutable reference
// which is guaranteed to be valid for writes.
// It is up to the caller to make sure that `slot` isn't dropped again.

View file

@ -1,4 +1,5 @@
use crate::any::type_name;
use crate::marker::Destruct;
use crate::mem::ManuallyDrop;
use crate::{fmt, intrinsics, ptr, slice};
@ -714,7 +715,11 @@ impl<T> MaybeUninit<T> {
///
/// [`assume_init`]: MaybeUninit::assume_init
#[stable(feature = "maybe_uninit_extra", since = "1.60.0")]
pub unsafe fn assume_init_drop(&mut self) {
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
pub const unsafe fn assume_init_drop(&mut self)
where
T: [const] Destruct,
{
// SAFETY: the caller must guarantee that `self` is initialized and
// satisfies all invariants of `T`.
// Dropping the value in place is safe if that is the case.
@ -1390,7 +1395,11 @@ impl<T> [MaybeUninit<T>] {
/// behaviour.
#[unstable(feature = "maybe_uninit_slice", issue = "63569")]
#[inline(always)]
pub unsafe fn assume_init_drop(&mut self) {
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
pub const unsafe fn assume_init_drop(&mut self)
where
T: [const] Destruct,
{
if !self.is_empty() {
// SAFETY: the caller must guarantee that every element of `self`
// is initialized and satisfies all invariants of `T`.

View file

@ -38,9 +38,8 @@ macro_rules! impl_full_ops {
fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) {
// This cannot overflow;
// the output is between `0` and `2^nbits * (2^nbits - 1)`.
let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) +
(carry as $bigty);
((v >> <$ty>::BITS) as $ty, v as $ty)
let (lo, hi) = self.carrying_mul_add(other, other2, carry);
(hi, lo)
}
fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) {

View file

@ -403,7 +403,7 @@
use crate::cmp::Ordering;
use crate::intrinsics::const_eval_select;
use crate::marker::{FnPtr, PointeeSized};
use crate::marker::{Destruct, FnPtr, PointeeSized};
use crate::mem::{self, MaybeUninit, SizedTypeProperties};
use crate::num::NonZero;
use crate::{fmt, hash, intrinsics, ub_checks};
@ -801,7 +801,11 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
#[lang = "drop_in_place"]
#[allow(unconditional_recursion)]
#[rustc_diagnostic_item = "ptr_drop_in_place"]
pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
pub const unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T)
where
T: [const] Destruct,
{
// Code here does not matter - this is replaced by the
// real drop glue by the compiler.

View file

@ -1,7 +1,7 @@
use super::*;
use crate::cmp::Ordering::{Equal, Greater, Less};
use crate::intrinsics::const_eval_select;
use crate::marker::PointeeSized;
use crate::marker::{Destruct, PointeeSized};
use crate::mem::{self, SizedTypeProperties};
use crate::slice::{self, SliceIndex};
@ -1390,8 +1390,12 @@ impl<T: PointeeSized> *mut T {
///
/// [`ptr::drop_in_place`]: crate::ptr::drop_in_place()
#[stable(feature = "pointer_methods", since = "1.26.0")]
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
#[inline(always)]
pub unsafe fn drop_in_place(self) {
pub const unsafe fn drop_in_place(self)
where
T: [const] Destruct,
{
// SAFETY: the caller must uphold the safety contract for `drop_in_place`.
unsafe { drop_in_place(self) }
}

View file

@ -1,5 +1,5 @@
use crate::cmp::Ordering;
use crate::marker::{PointeeSized, Unsize};
use crate::marker::{Destruct, PointeeSized, Unsize};
use crate::mem::{MaybeUninit, SizedTypeProperties};
use crate::num::NonZero;
use crate::ops::{CoerceUnsized, DispatchFromDyn};
@ -1118,7 +1118,11 @@ impl<T: PointeeSized> NonNull<T> {
/// [`ptr::drop_in_place`]: crate::ptr::drop_in_place()
#[inline(always)]
#[stable(feature = "non_null_convenience", since = "1.80.0")]
pub unsafe fn drop_in_place(self) {
#[rustc_const_unstable(feature = "const_drop_in_place", issue = "109342")]
pub const unsafe fn drop_in_place(self)
where
T: [const] Destruct,
{
// SAFETY: the caller must uphold the safety contract for `drop_in_place`.
unsafe { ptr::drop_in_place(self.as_ptr()) }
}

View file

@ -19,6 +19,7 @@
#![feature(const_cmp)]
#![feature(const_convert)]
#![feature(const_destruct)]
#![feature(const_drop_in_place)]
#![feature(const_eval_select)]
#![feature(const_mul_add)]
#![feature(const_ops)]

View file

@ -1,6 +1,6 @@
use core::cell::RefCell;
use core::marker::Freeze;
use core::mem::MaybeUninit;
use core::mem::{ManuallyDrop, MaybeUninit};
use core::num::NonZero;
use core::ptr;
use core::ptr::*;
@ -1045,3 +1045,42 @@ fn test_ptr_default() {
let default = PtrMutDefaultTest::default();
assert!(default.ptr.is_null());
}
#[test]
fn test_const_drop_in_place() {
const COUNTER: usize = {
let mut counter = 0;
let counter_ptr = &raw mut counter;
// only exists to make `Drop` indirect impl
#[allow(dead_code)]
struct Test(Dropped);
struct Dropped(*mut usize);
impl const Drop for Dropped {
fn drop(&mut self) {
unsafe {
*self.0 += 1;
}
}
}
let mut one = ManuallyDrop::new(Test(Dropped(counter_ptr)));
let mut two = ManuallyDrop::new(Test(Dropped(counter_ptr)));
let mut three = ManuallyDrop::new(Test(Dropped(counter_ptr)));
assert!(counter == 0);
unsafe {
ManuallyDrop::drop(&mut one);
}
assert!(counter == 1);
unsafe {
ManuallyDrop::drop(&mut two);
}
assert!(counter == 2);
unsafe {
ManuallyDrop::drop(&mut three);
}
counter
};
assert_eq!(COUNTER, 3);
}

View file

@ -33,7 +33,7 @@ miniz_oxide = { version = "0.8.0", optional = true, default-features = false }
addr2line = { version = "0.25.0", optional = true, default-features = false }
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
libc = { version = "0.2.172", default-features = false, features = [
libc = { version = "0.2.177", default-features = false, features = [
'rustc-dep-of-std',
], public = true }

View file

@ -358,9 +358,10 @@ fn default_alloc_error_hook(layout: Layout) {
// This is the default path taken on OOM, and the only path taken on stable with std.
// Crucially, it does *not* call any user-defined code, and therefore users do not have to
// worry about allocation failure causing reentrancy issues. That makes it different from
// the default `__rdl_oom` defined in alloc (i.e., the default alloc error handler that is
// called when there is no `#[alloc_error_handler]`), which triggers a regular panic and
// thus can invoke a user-defined panic hook, executing arbitrary user-defined code.
// the default `__rdl_alloc_error_handler` defined in alloc (i.e., the default alloc error
// handler that is called when there is no `#[alloc_error_handler]`), which triggers a
// regular panic and thus can invoke a user-defined panic hook, executing arbitrary
// user-defined code.
rtprintpanic!("memory allocation of {} bytes failed\n", layout.size());
}
}

View file

@ -65,7 +65,7 @@
//! So for example there is a [page for the primitive type
//! `char`](primitive::char) that lists all the methods that can be called on
//! characters (very useful), and there is a [page for the module
//! `std::char`] that documents iterator and error types created by these methods
//! `std::char`](crate::char) that documents iterator and error types created by these methods
//! (rarely useful).
//!
//! Note the documentation for the primitives [`str`] and [`[T]`][prim@slice] (also
@ -180,9 +180,6 @@
//!
//!
//! [I/O]: io
//! [`MIN`]: i32::MIN
//! [`MAX`]: i32::MAX
//! [page for the module `std::i32`]: crate::i32
//! [TCP]: net::TcpStream
//! [The Rust Prelude]: prelude
//! [UDP]: net::UdpSocket

View file

@ -1,11 +1,6 @@
use super::Mutex;
use crate::cell::UnsafeCell;
use crate::pin::Pin;
#[cfg(not(target_os = "nto"))]
use crate::sys::pal::time::TIMESPEC_MAX;
#[cfg(target_os = "nto")]
use crate::sys::pal::time::TIMESPEC_MAX_CAPPED;
use crate::sys::pal::time::Timespec;
use crate::time::Duration;
pub struct Condvar {
@ -47,27 +42,29 @@ impl Condvar {
let r = unsafe { libc::pthread_cond_wait(self.raw(), mutex.raw()) };
debug_assert_eq!(r, 0);
}
}
#[cfg(not(target_vendor = "apple"))]
impl Condvar {
/// # Safety
/// * `init` must have been called on this instance.
/// * `mutex` must be locked by the current thread.
/// * This condition variable may only be used with the same mutex.
pub unsafe fn wait_timeout(&self, mutex: Pin<&Mutex>, dur: Duration) -> bool {
#[cfg(not(target_os = "nto"))]
use crate::sys::pal::time::TIMESPEC_MAX;
#[cfg(target_os = "nto")]
use crate::sys::pal::time::TIMESPEC_MAX_CAPPED;
use crate::sys::pal::time::Timespec;
let mutex = mutex.raw();
// OSX implementation of `pthread_cond_timedwait` is buggy
// with super long durations. When duration is greater than
// 0x100_0000_0000_0000 seconds, `pthread_cond_timedwait`
// in macOS Sierra returns error 316.
//
// This program demonstrates the issue:
// https://gist.github.com/stepancheg/198db4623a20aad2ad7cddb8fda4a63c
//
// To work around this issue, the timeout is clamped to 1000 years.
//
// Cygwin implementation is based on NT API and a super large timeout
// makes the syscall block forever.
#[cfg(any(target_vendor = "apple", target_os = "cygwin"))]
// Cygwin's implementation is based on the NT API, which measures time
// in units of 100 ns. Unfortunately, Cygwin does not properly guard
// against overflow when converting the time, hence we clamp the interval
// to 1000 years, which will only become a problem in around 27000 years,
// when the next rollover is less than 1000 years away...
#[cfg(target_os = "cygwin")]
let dur = Duration::min(dur, Duration::from_secs(1000 * 365 * 86400));
let timeout = Timespec::now(Self::CLOCK).checked_add_duration(&dur);
@ -84,6 +81,57 @@ impl Condvar {
}
}
// Apple platforms (since macOS version 10.4 and iOS version 2.0) have
// `pthread_cond_timedwait_relative_np`, a non-standard extension that
// measures timeouts based on the monotonic clock and is thus resilient
// against wall-clock changes.
#[cfg(target_vendor = "apple")]
impl Condvar {
/// # Safety
/// * `init` must have been called on this instance.
/// * `mutex` must be locked by the current thread.
/// * This condition variable may only be used with the same mutex.
pub unsafe fn wait_timeout(&self, mutex: Pin<&Mutex>, dur: Duration) -> bool {
let mutex = mutex.raw();
// The macOS implementation of `pthread_cond_timedwait` internally
// converts the timeout passed to `pthread_cond_timedwait_relative_np`
// to nanoseconds. Unfortunately, the "psynch" variant of condvars does
// not guard against overflow during the conversion[^1], which means
// that `pthread_cond_timedwait_relative_np` will return `ETIMEDOUT`
// much earlier than expected if the relative timeout is longer than
// `u64::MAX` nanoseconds.
//
// This can be observed even on newer platforms (by setting the environment
// variable PTHREAD_MUTEX_USE_ULOCK to a value other than "1") by calling e.g.
// ```
// condvar.wait_timeout(..., Duration::from_secs(u64::MAX.div_ceil(1_000_000_000));
// ```
// (see #37440, especially
// https://github.com/rust-lang/rust/issues/37440#issuecomment-3285958326).
//
// To work around this issue, always clamp the timeout to u64::MAX nanoseconds,
// even if the "ulock" variant is used (which does guard against overflow).
//
// [^1]: https://github.com/apple-oss-distributions/libpthread/blob/1ebf56b3a702df53213c2996e5e128a535d2577e/kern/kern_synch.c#L1269
const MAX_DURATION: Duration = Duration::from_nanos(u64::MAX);
let (dur, clamped) = if dur <= MAX_DURATION { (dur, false) } else { (MAX_DURATION, true) };
let timeout = libc::timespec {
// This cannot overflow because of the clamping above.
tv_sec: dur.as_secs() as i64,
tv_nsec: dur.subsec_nanos() as i64,
};
let r = unsafe { libc::pthread_cond_timedwait_relative_np(self.raw(), mutex, &timeout) };
assert!(r == libc::ETIMEDOUT || r == 0);
// Report clamping as a spurious wakeup. Who knows, maybe some
// interstellar space probe will rely on this ;-).
r == 0 || clamped
}
}
#[cfg(not(any(
target_os = "android",
target_vendor = "apple",
@ -125,10 +173,23 @@ impl Condvar {
}
}
#[cfg(target_vendor = "apple")]
impl Condvar {
// `pthread_cond_timedwait_relative_np` measures the timeout
// based on the monotonic clock.
pub const PRECISE_TIMEOUT: bool = true;
/// # Safety
/// May only be called once per instance of `Self`.
pub unsafe fn init(self: Pin<&mut Self>) {
// `PTHREAD_COND_INITIALIZER` is fully supported and we don't need to
// change clocks, so there's nothing to do here.
}
}
// `pthread_condattr_setclock` is unfortunately not supported on these platforms.
#[cfg(any(
target_os = "android",
target_vendor = "apple",
target_os = "espidf",
target_os = "horizon",
target_os = "l4re",

View file

@ -267,3 +267,35 @@ nonpoison_and_poison_unwrap_test!(
}
}
);
// Some platforms internally cast the timeout duration into nanoseconds.
// If they fail to consider overflow during the conversion (I'm looking
// at you, macOS), `wait_timeout` will return immediately and indicate a
// timeout for durations that are slightly longer than u64::MAX nanoseconds.
// `std` should guard against this by clamping the timeout.
// See #37440 for context.
nonpoison_and_poison_unwrap_test!(
name: timeout_nanoseconds,
test_body: {
use locks::Mutex;
use locks::Condvar;
let sent = Mutex::new(false);
let cond = Condvar::new();
thread::scope(|s| {
s.spawn(|| {
thread::sleep(Duration::from_secs(2));
maybe_unwrap(sent.set(true));
cond.notify_all();
});
let guard = maybe_unwrap(sent.lock());
// If there is internal overflow, this call will return almost
// immediately, before the other thread has reached the `notify_all`
let (guard, res) = maybe_unwrap(cond.wait_timeout(guard, Duration::from_secs(u64::MAX.div_ceil(1_000_000_000))));
assert!(!res.timed_out());
assert!(*guard);
})
}
);

View file

@ -3,7 +3,7 @@ use std::io::Write;
use std::path::Path;
use rustc_abi::{Align, AlignFromBytesError, CanonAbi, Size};
use rustc_ast::expand::allocator::alloc_error_handler_name;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_hir::attrs::Linkage;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::CrateNum;
@ -52,6 +52,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Some shims forward to other MIR bodies.
match link_name.as_str() {
// This allocator function has forwarding shims synthesized during normal codegen
// (see `allocator_shim_contents`); this is where we emulate that behavior.
// FIXME should use global_fn_name, but mangle_internal_symbol requires a static str.
name if name == this.mangle_internal_symbol("__rust_alloc_error_handler") => {
// Forward to the right symbol that implements this function.
let Some(handler_kind) = this.tcx.alloc_error_handler_kind(()) else {
@ -60,12 +63,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"`__rust_alloc_error_handler` cannot be called when no alloc error handler is set"
);
};
let name = Symbol::intern(
this.mangle_internal_symbol(alloc_error_handler_name(handler_kind)),
);
let handler =
this.lookup_exported_symbol(name)?.expect("missing alloc error handler symbol");
return interp_ok(Some(handler));
if handler_kind == AllocatorKind::Default {
let name =
Symbol::intern(this.mangle_internal_symbol("__rdl_alloc_error_handler"));
let handler = this
.lookup_exported_symbol(name)?
.expect("missing alloc error handler symbol");
return interp_ok(Some(handler));
}
// Fall through to the `lookup_exported_symbol` below which should find
// a `__rust_alloc_error_handler`.
}
_ => {}
}

View file

@ -815,7 +815,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"pthread_cond_timedwait" => {
let [cond, mutex, abstime] =
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_cond_timedwait(cond, mutex, abstime, dest)?;
this.pthread_cond_timedwait(cond, mutex, abstime, dest, /* macos_relative_np */ false)?;
}
"pthread_cond_destroy" => {
let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;

View file

@ -307,6 +307,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.os_unfair_lock_assert_not_owner(lock_op)?;
}
"pthread_cond_timedwait_relative_np" => {
let [cond, mutex, reltime] =
this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?;
this.pthread_cond_timedwait(cond, mutex, reltime, dest, /* macos_relative_np */ true)?;
}
_ => return interp_ok(EmulateItemResult::NotSupported),
};

View file

@ -834,8 +834,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
&mut self,
cond_op: &OpTy<'tcx>,
mutex_op: &OpTy<'tcx>,
abstime_op: &OpTy<'tcx>,
timeout_op: &OpTy<'tcx>,
dest: &MPlaceTy<'tcx>,
macos_relative_np: bool,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
@ -844,7 +845,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Extract the timeout.
let duration = match this
.read_timespec(&this.deref_pointer_as(abstime_op, this.libc_ty_layout("timespec"))?)?
.read_timespec(&this.deref_pointer_as(timeout_op, this.libc_ty_layout("timespec"))?)?
{
Some(duration) => duration,
None => {
@ -853,14 +854,23 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
return interp_ok(());
}
};
if data.clock == TimeoutClock::RealTime {
this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?;
}
let (clock, anchor) = if macos_relative_np {
// `pthread_cond_timedwait_relative_np` always measures time against the
// monotonic clock, regardless of the condvar clock.
(TimeoutClock::Monotonic, TimeoutAnchor::Relative)
} else {
if data.clock == TimeoutClock::RealTime {
this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?;
}
(data.clock, TimeoutAnchor::Absolute)
};
this.condvar_wait(
data.condvar_ref,
mutex_ref,
Some((data.clock, TimeoutAnchor::Absolute, duration)),
Some((clock, anchor, duration)),
Scalar::from_i32(0),
this.eval_libc("ETIMEDOUT"), // retval_timeout
dest.clone(),

View file

@ -7,7 +7,7 @@ LL | crate::process::abort()
|
= note: BACKTRACE:
= note: inside `std::alloc::rust_oom` at RUSTLIB/std/src/alloc.rs:LL:CC
= note: inside `std::alloc::_::__rg_oom` at RUSTLIB/std/src/alloc.rs:LL:CC
= note: inside `std::alloc::_::__rust_alloc_error_handler` at RUSTLIB/std/src/alloc.rs:LL:CC
= note: inside `std::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `std::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
note: inside `main`

View file

@ -7,7 +7,7 @@ LL | core::intrinsics::abort();
|
= note: BACKTRACE:
= note: inside `alloc_error_handler` at tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC
note: inside `_::__rg_oom`
note: inside `_::__rust_alloc_error_handler`
--> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC
|
LL | #[alloc_error_handler]

View file

@ -9,7 +9,7 @@ LL | core::intrinsics::abort();
|
= note: BACKTRACE:
= note: inside `panic_handler` at tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC
= note: inside `alloc::alloc::__alloc_error_handler::__rdl_oom` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `alloc::alloc::__alloc_error_handler::__rdl_alloc_error_handler` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
= note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC
note: inside `miri_start`

View file

@ -1,8 +1,10 @@
error: Undefined Behavior: trying to retag from <TAG> for Unique permission at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location
--> RUSTLIB/core/src/ptr/mod.rs:LL:CC
|
LL | pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this error occurs as part of retag at ALLOC[0x0..0x1]
LL | / pub const unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T)
LL | | where
LL | | T: [const] Destruct,
| |________________________^ this error occurs as part of retag at ALLOC[0x0..0x1]
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information

View file

@ -1,8 +1,10 @@
error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN)
--> RUSTLIB/core/src/ptr/mod.rs:LL:CC
|
LL | pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
LL | / pub const unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T)
LL | | where
LL | | T: [const] Destruct,
| |________________________^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

View file

@ -0,0 +1,41 @@
//@only-target: apple # `pthread_cond_timedwait_relative_np` is a non-standard extension
use std::time::Instant;
// FIXME: remove once this is in libc.
mod libc {
pub use ::libc::*;
unsafe extern "C" {
pub unsafe fn pthread_cond_timedwait_relative_np(
cond: *mut libc::pthread_cond_t,
lock: *mut libc::pthread_mutex_t,
timeout: *const libc::timespec,
) -> libc::c_int;
}
}
fn main() {
unsafe {
let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
let mut cond: libc::pthread_cond_t = libc::PTHREAD_COND_INITIALIZER;
// Wait for 100 ms.
let timeout = libc::timespec { tv_sec: 0, tv_nsec: 100_000_000 };
assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
let current_time = Instant::now();
assert_eq!(
libc::pthread_cond_timedwait_relative_np(&mut cond, &mut mutex, &timeout),
libc::ETIMEDOUT
);
let elapsed_time = current_time.elapsed().as_millis();
// This is actually deterministic (since isolation remains enabled),
// but can change slightly with Rust updates.
assert!(90 <= elapsed_time && elapsed_time <= 110);
assert_eq!(libc::pthread_mutex_unlock(&mut mutex), 0);
assert_eq!(libc::pthread_mutex_destroy(&mut mutex), 0);
assert_eq!(libc::pthread_cond_destroy(&mut cond), 0);
}
}

View file

@ -0,0 +1,43 @@
// Checks that results larger than one register are returned indirectly
//@ only-bpf
//@ needs-llvm-components: bpf
//@ compile-flags: --target bpfel-unknown-none
#![no_std]
#![no_main]
#[no_mangle]
fn outer(a: u64) -> u64 {
let v = match inner_res(a) {
Ok(v) => v,
Err(()) => 0,
};
inner_big(v).a[0] as u64
}
// CHECK-LABEL: define {{.*}} @_ZN{{.*}}inner_res{{.*}}E(
// CHECK-SAME: ptr{{[^,]*}},
// CHECK-SAME: i64{{[^)]*}}
#[inline(never)]
fn inner_res(a: u64) -> Result<u64, ()> {
if a == 0 { Err(()) } else { Ok(a + 1) }
}
struct Big {
a: [u16; 32],
b: u64,
}
// CHECK-LABEL: define {{.*}} @_ZN{{.*}}inner_big{{.*}}E(
// CHECK-SAME: ptr{{[^,]*}},
// CHECK-SAME: i64{{[^)]*}}
#[inline(never)]
fn inner_big(a: u64) -> Big {
Big { a: [a as u16; 32], b: 42 }
}
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}

View file

@ -14,5 +14,5 @@ fn main() {
let out = llvm_readobj().input("app.o").arg("--symbols").run();
out.assert_stdout_contains("rust_begin_unwind");
out.assert_stdout_contains("rust_eh_personality");
out.assert_stdout_contains("__rg_oom");
out.assert_stdout_contains("__rust_alloc_error_handler");
}

View file

@ -10,7 +10,7 @@
#![macro_export]
//~^ ERROR: `#[macro_export]` attribute cannot be used on crates
#![rustc_main]
//~^ ERROR: `rustc_main` attribute cannot be used at crate level
//~^ ERROR: `#[rustc_main]` attribute cannot be used on crates
//~| ERROR: use of an internal attribute [E0658]
//~| NOTE: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable
//~| NOTE: the `#[rustc_main]` attribute is used internally to specify test entry point function
@ -31,7 +31,6 @@
//~^ ERROR attribute cannot be used on
mod inline {
//~^ NOTE the inner attribute doesn't annotate this module
//~| NOTE the inner attribute doesn't annotate this module
mod inner { #![inline] }
//~^ ERROR attribute cannot be used on

View file

@ -16,6 +16,14 @@ LL | #![macro_export]
|
= help: `#[macro_export]` can only be applied to macro defs
error: `#[rustc_main]` attribute cannot be used on crates
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1
|
LL | #![rustc_main]
| ^^^^^^^^^^^^^^
|
= help: `#[rustc_main]` can only be applied to functions
error: `#[path]` attribute cannot be used on crates
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
|
@ -57,7 +65,7 @@ LL | #[inline]
= help: `#[inline]` can only be applied to functions
error: `#[inline]` attribute cannot be used on modules
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:17
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:35:17
|
LL | mod inner { #![inline] }
| ^^^^^^^^^^
@ -65,7 +73,7 @@ LL | mod inner { #![inline] }
= help: `#[inline]` can only be applied to functions
error: `#[inline]` attribute cannot be used on structs
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:45:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:44:5
|
LL | #[inline] struct S;
| ^^^^^^^^^
@ -73,7 +81,7 @@ LL | #[inline] struct S;
= help: `#[inline]` can only be applied to functions
error: `#[inline]` attribute cannot be used on type aliases
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:48:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:47:5
|
LL | #[inline] type T = S;
| ^^^^^^^^^
@ -81,7 +89,7 @@ LL | #[inline] type T = S;
= help: `#[inline]` can only be applied to functions
error: `#[inline]` attribute cannot be used on inherent impl blocks
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:51:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5
|
LL | #[inline] impl S { }
| ^^^^^^^^^
@ -89,7 +97,7 @@ LL | #[inline] impl S { }
= help: `#[inline]` can only be applied to functions
error: `#[export_name]` attribute cannot be used on modules
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:81:1
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:1
|
LL | #[export_name = "2200"]
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -97,7 +105,7 @@ LL | #[export_name = "2200"]
= help: `#[export_name]` can be applied to functions and statics
error: `#[export_name]` attribute cannot be used on modules
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:84:17
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:83:17
|
LL | mod inner { #![export_name="2200"] }
| ^^^^^^^^^^^^^^^^^^^^^^
@ -105,7 +113,7 @@ LL | mod inner { #![export_name="2200"] }
= help: `#[export_name]` can be applied to functions and statics
error: `#[export_name]` attribute cannot be used on structs
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:88:5
|
LL | #[export_name = "2200"] struct S;
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -113,7 +121,7 @@ LL | #[export_name = "2200"] struct S;
= help: `#[export_name]` can be applied to functions and statics
error: `#[export_name]` attribute cannot be used on type aliases
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:92:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:5
|
LL | #[export_name = "2200"] type T = S;
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -121,7 +129,7 @@ LL | #[export_name = "2200"] type T = S;
= help: `#[export_name]` can be applied to functions and statics
error: `#[export_name]` attribute cannot be used on inherent impl blocks
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:95:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:94:5
|
LL | #[export_name = "2200"] impl S { }
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -129,7 +137,7 @@ LL | #[export_name = "2200"] impl S { }
= help: `#[export_name]` can be applied to functions and statics
error: `#[export_name]` attribute cannot be used on required trait methods
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:99:9
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:98:9
|
LL | #[export_name = "2200"] fn foo();
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -137,7 +145,7 @@ LL | #[export_name = "2200"] fn foo();
= help: `#[export_name]` can be applied to functions, inherent methods, provided trait methods, statics, and trait methods in impl blocks
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:55:1
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:1
|
LL | #[no_link]
| ^^^^^^^^^^
@ -151,7 +159,7 @@ LL | | }
| |_- not an `extern crate` item
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:8
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:105:8
|
LL | #[repr(C)]
| ^
@ -164,7 +172,7 @@ LL | | }
| |_- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:130:8
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:8
|
LL | #[repr(Rust)]
| ^^^^
@ -182,21 +190,6 @@ error: attribute should be applied to an `extern crate` item
LL | #![no_link]
| ^^^^^^^^^^^ not an `extern crate` item
error: `rustc_main` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:12:1
|
LL | #![rustc_main]
| ^^^^^^^^^^^^^^
...
LL | mod inline {
| ------ the inner attribute doesn't annotate this module
|
help: perhaps you meant to use an outer attribute
|
LL - #![rustc_main]
LL + #[rustc_main]
|
error: `repr` attribute cannot be used at crate level
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
|
@ -213,85 +206,85 @@ LL + #[repr()]
|
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:60:17
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:59:17
|
LL | mod inner { #![no_link] }
| ------------^^^^^^^^^^^-- not an `extern crate` item
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:64:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:63:5
|
LL | #[no_link] fn f() { }
| ^^^^^^^^^^ ---------- not an `extern crate` item
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:67:5
|
LL | #[no_link] struct S;
| ^^^^^^^^^^ --------- not an `extern crate` item
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:71:5
|
LL | #[no_link]type T = S;
| ^^^^^^^^^^----------- not an `extern crate` item
error: attribute should be applied to an `extern crate` item
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:75:5
|
LL | #[no_link] impl S { }
| ^^^^^^^^^^ ---------- not an `extern crate` item
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:25
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:109:25
|
LL | mod inner { #![repr(C)] }
| --------------------^---- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:114:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:12
|
LL | #[repr(C)] fn f() { }
| ^ ---------- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:120:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:119:12
|
LL | #[repr(C)] type T = S;
| ^ ----------- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:124:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:123:12
|
LL | #[repr(C)] impl S { }
| ^ ---------- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:134:25
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:133:25
|
LL | mod inner { #![repr(Rust)] }
| --------------------^^^^---- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:138:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:12
|
LL | #[repr(Rust)] fn f() { }
| ^^^^ ---------- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:144:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:143:12
|
LL | #[repr(Rust)] type T = S;
| ^^^^ ----------- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:148:12
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:12
|
LL | #[repr(Rust)] impl S { }
| ^^^^ ---------- not a struct, enum, or union
error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:39:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:38:5
|
LL | #[inline = "2100"] fn f() { }
| ^^^^^^^^^^^^^^^^^^
@ -306,7 +299,7 @@ Some errors have detailed explanations: E0517, E0658.
For more information about an error, try `rustc --explain E0517`.
Future incompatibility report: Future breakage diagnostic:
error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:39:5
--> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:38:5
|
LL | #[inline = "2100"] fn f() { }
| ^^^^^^^^^^^^^^^^^^

View file

@ -490,16 +490,6 @@ fun:__dfso_*=uninstrumented
fun:__dfso_*=discard
# Rust functions.
fun:__rdl_alloc=uninstrumented
fun:__rdl_alloc_zeroed=uninstrumented
fun:__rdl_dealloc=uninstrumented
fun:__rdl_realloc=uninstrumented
fun:__rg_oom=uninstrumented
fun:__rust_alloc=uninstrumented
fun:__rust_alloc_error_handler=uninstrumented
fun:__rust_alloc_zeroed=uninstrumented
fun:__rust_dealloc=uninstrumented
fun:__rust_realloc=uninstrumented
fun:_ZN4core*=uninstrumented
fun:_ZN3std*=uninstrumented
fun:rust_eh_personality=uninstrumented

View file

@ -0,0 +1,11 @@
// ICE #147325: When the user mistakenly uses struct syntax to construct an enum,
// the field_idents and field_defaults functions will trigger an error
mod m {
struct Priv1;
}
fn main() {
Option { field1: m::Priv1 } //~ ERROR expected struct, variant or union type, found enum
//~^ ERROR unit struct `Priv1` is private
}

View file

@ -0,0 +1,22 @@
error[E0574]: expected struct, variant or union type, found enum `Option`
--> $DIR/struct-fields-ice-147325.rs:9:5
|
LL | Option { field1: m::Priv1 }
| ^^^^^^ not a struct, variant or union type
error[E0603]: unit struct `Priv1` is private
--> $DIR/struct-fields-ice-147325.rs:9:25
|
LL | Option { field1: m::Priv1 }
| ^^^^^ private unit struct
|
note: the unit struct `Priv1` is defined here
--> $DIR/struct-fields-ice-147325.rs:5:5
|
LL | struct Priv1;
| ^^^^^^^^^^^^^
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0574, E0603.
For more information about an error, try `rustc --explain E0574`.