Auto merge of #3042 - rust-lang:rustup-2023-08-29, r=RalfJung

Automatic sync from rustc
This commit is contained in:
bors 2023-08-29 05:55:46 +00:00
commit d9c11c65ee
307 changed files with 2401 additions and 1416 deletions

View File

@ -236,7 +236,7 @@ enum ImplTraitContext {
ReturnPositionOpaqueTy { ReturnPositionOpaqueTy {
/// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn, /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
origin: hir::OpaqueTyOrigin, origin: hir::OpaqueTyOrigin,
in_trait: bool, fn_kind: FnDeclKind,
}, },
/// Impl trait in type aliases. /// Impl trait in type aliases.
TypeAliasesOpaqueTy { in_assoc_ty: bool }, TypeAliasesOpaqueTy { in_assoc_ty: bool },
@ -312,7 +312,7 @@ impl std::fmt::Display for ImplTraitPosition {
} }
} }
#[derive(Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum FnDeclKind { enum FnDeclKind {
Fn, Fn,
Inherent, Inherent,
@ -1401,13 +1401,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TyKind::ImplTrait(def_node_id, bounds) => { TyKind::ImplTrait(def_node_id, bounds) => {
let span = t.span; let span = t.span;
match itctx { match itctx {
ImplTraitContext::ReturnPositionOpaqueTy { origin, in_trait } => self ImplTraitContext::ReturnPositionOpaqueTy { origin, fn_kind } => self
.lower_opaque_impl_trait( .lower_opaque_impl_trait(
span, span,
*origin, *origin,
*def_node_id, *def_node_id,
bounds, bounds,
*in_trait, Some(*fn_kind),
itctx, itctx,
), ),
&ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self
@ -1416,7 +1416,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::OpaqueTyOrigin::TyAlias { in_assoc_ty }, hir::OpaqueTyOrigin::TyAlias { in_assoc_ty },
*def_node_id, *def_node_id,
bounds, bounds,
false, None,
itctx, itctx,
), ),
ImplTraitContext::Universal => { ImplTraitContext::Universal => {
@ -1523,7 +1523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
origin: hir::OpaqueTyOrigin, origin: hir::OpaqueTyOrigin,
opaque_ty_node_id: NodeId, opaque_ty_node_id: NodeId,
bounds: &GenericBounds, bounds: &GenericBounds,
in_trait: bool, fn_kind: Option<FnDeclKind>,
itctx: &ImplTraitContext, itctx: &ImplTraitContext,
) -> hir::TyKind<'hir> { ) -> hir::TyKind<'hir> {
// Make sure we know that some funky desugaring has been going on here. // Make sure we know that some funky desugaring has been going on here.
@ -1540,10 +1540,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
Vec::new() Vec::new()
} }
hir::OpaqueTyOrigin::FnReturn(..) => { hir::OpaqueTyOrigin::FnReturn(..) => {
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a` if let FnDeclKind::Impl | FnDeclKind::Trait =
// example, we only need to duplicate lifetimes that appear in the fn_kind.expect("expected RPITs to be lowered with a FnKind")
// bounds, since those are the only ones that are captured by the opaque. {
lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds) // return-position impl trait in trait was decided to capture all
// in-scope lifetimes, which we collect for all opaques during resolution.
self.resolver
.take_extra_lifetime_params(opaque_ty_node_id)
.into_iter()
.map(|(ident, id, _)| Lifetime { id, ident })
.collect()
} else {
// in fn return position, like the `fn test<'a>() -> impl Debug + 'a`
// example, we only need to duplicate lifetimes that appear in the
// bounds, since those are the only ones that are captured by the opaque.
lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
}
} }
hir::OpaqueTyOrigin::AsyncFn(..) => { hir::OpaqueTyOrigin::AsyncFn(..) => {
unreachable!("should be using `lower_async_fn_ret_ty`") unreachable!("should be using `lower_async_fn_ret_ty`")
@ -1554,7 +1566,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.lower_opaque_inner( self.lower_opaque_inner(
opaque_ty_node_id, opaque_ty_node_id,
origin, origin,
in_trait, matches!(fn_kind, Some(FnDeclKind::Trait)),
captured_lifetimes_to_duplicate, captured_lifetimes_to_duplicate,
span, span,
opaque_ty_span, opaque_ty_span,
@ -1802,12 +1814,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} }
let fn_def_id = self.local_def_id(fn_node_id); let fn_def_id = self.local_def_id(fn_node_id);
self.lower_async_fn_ret_ty( self.lower_async_fn_ret_ty(&decl.output, fn_def_id, ret_id, kind)
&decl.output,
fn_def_id,
ret_id,
matches!(kind, FnDeclKind::Trait),
)
} else { } else {
match &decl.output { match &decl.output {
FnRetTy::Ty(ty) => { FnRetTy::Ty(ty) => {
@ -1815,7 +1822,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let fn_def_id = self.local_def_id(fn_node_id); let fn_def_id = self.local_def_id(fn_node_id);
ImplTraitContext::ReturnPositionOpaqueTy { ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
in_trait: matches!(kind, FnDeclKind::Trait), fn_kind: kind,
} }
} else { } else {
let position = match kind { let position = match kind {
@ -1883,7 +1890,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
output: &FnRetTy, output: &FnRetTy,
fn_def_id: LocalDefId, fn_def_id: LocalDefId,
opaque_ty_node_id: NodeId, opaque_ty_node_id: NodeId,
in_trait: bool, fn_kind: FnDeclKind,
) -> hir::FnRetTy<'hir> { ) -> hir::FnRetTy<'hir> {
let span = self.lower_span(output.span()); let span = self.lower_span(output.span());
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None); let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None);
@ -1898,7 +1905,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let opaque_ty_ref = self.lower_opaque_inner( let opaque_ty_ref = self.lower_opaque_inner(
opaque_ty_node_id, opaque_ty_node_id,
hir::OpaqueTyOrigin::AsyncFn(fn_def_id), hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
in_trait, matches!(fn_kind, FnDeclKind::Trait),
captured_lifetimes, captured_lifetimes,
span, span,
opaque_ty_span, opaque_ty_span,
@ -1906,7 +1913,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let future_bound = this.lower_async_fn_output_type_to_future_bound( let future_bound = this.lower_async_fn_output_type_to_future_bound(
output, output,
span, span,
if in_trait && !this.tcx.features().return_position_impl_trait_in_trait { if let FnDeclKind::Trait = fn_kind
&& !this.tcx.features().return_position_impl_trait_in_trait
{
ImplTraitContext::FeatureGated( ImplTraitContext::FeatureGated(
ImplTraitPosition::TraitReturn, ImplTraitPosition::TraitReturn,
sym::return_position_impl_trait_in_trait, sym::return_position_impl_trait_in_trait,
@ -1914,7 +1923,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
} else { } else {
ImplTraitContext::ReturnPositionOpaqueTy { ImplTraitContext::ReturnPositionOpaqueTy {
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
in_trait, fn_kind,
} }
}, },
); );

View File

@ -217,7 +217,7 @@ pub fn expand_include_bytes(
}; };
match cx.source_map().load_binary_file(&file) { match cx.source_map().load_binary_file(&file) {
Ok(bytes) => { Ok(bytes) => {
let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes.into())); let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes));
base::MacEager::expr(expr) base::MacEager::expr(expr)
} }
Err(e) => { Err(e) => {

View File

@ -39,7 +39,7 @@ fn clif_sig_from_fn_abi<'tcx>(
pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv { pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv {
match c { match c {
Conv::Rust | Conv::C => default_call_conv, Conv::Rust | Conv::C => default_call_conv,
Conv::RustCold => CallConv::Cold, Conv::Cold | Conv::PreserveMost | Conv::PreserveAll => CallConv::Cold,
Conv::X86_64SysV => CallConv::SystemV, Conv::X86_64SysV => CallConv::SystemV,
Conv::X86_64Win64 => CallConv::WindowsFastcall, Conv::X86_64Win64 => CallConv::WindowsFastcall,

View File

@ -125,8 +125,8 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
PassMode::Ignore => continue, PassMode::Ignore => continue,
PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx), PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx),
PassMode::Pair(..) => { PassMode::Pair(..) => {
argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0, true)); argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0));
argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1, true)); argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1));
continue; continue;
} }
PassMode::Indirect { extra_attrs: Some(_), .. } => { PassMode::Indirect { extra_attrs: Some(_), .. } => {

View File

@ -821,7 +821,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
let mut load = |i, scalar: &abi::Scalar, align| { let mut load = |i, scalar: &abi::Scalar, align| {
let llptr = self.struct_gep(pair_type, place.llval, i as u64); let llptr = self.struct_gep(pair_type, place.llval, i as u64);
let llty = place.layout.scalar_pair_element_gcc_type(self, i, false); let llty = place.layout.scalar_pair_element_gcc_type(self, i);
let load = self.load(llty, llptr, align); let load = self.load(llty, llptr, align);
scalar_load_metadata(self, load, scalar); scalar_load_metadata(self, load, scalar);
if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load } if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load }

View File

@ -55,7 +55,7 @@ impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
_llfn: RValue<'gcc>, _llfn: RValue<'gcc>,
_mir: &mir::Body<'tcx>, _mir: &mir::Body<'tcx>,
) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>> { ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> {
// TODO(antoyo) // TODO(antoyo)
None None
} }

View File

@ -4,7 +4,7 @@ use gccjit::{Struct, Type};
use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods}; use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods};
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_target::abi::{self, Abi, Align, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants}; use rustc_target::abi::{self, Abi, Align, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants};
use rustc_target::abi::call::{CastTarget, FnAbi, Reg}; use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
@ -74,8 +74,8 @@ fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
Abi::ScalarPair(..) => { Abi::ScalarPair(..) => {
return cx.type_struct( return cx.type_struct(
&[ &[
layout.scalar_pair_element_gcc_type(cx, 0, false), layout.scalar_pair_element_gcc_type(cx, 0),
layout.scalar_pair_element_gcc_type(cx, 1, false), layout.scalar_pair_element_gcc_type(cx, 1),
], ],
false, false,
); );
@ -150,7 +150,7 @@ pub trait LayoutGccExt<'tcx> {
fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>; fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>; fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>;
fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc>; fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize) -> Type<'gcc>;
fn gcc_field_index(&self, index: usize) -> u64; fn gcc_field_index(&self, index: usize) -> u64;
fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option<PointeeInfo>; fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option<PointeeInfo>;
} }
@ -182,23 +182,16 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
/// of that field's type - this is useful for taking the address of /// of that field's type - this is useful for taking the address of
/// that field and ensuring the struct has the right alignment. /// that field and ensuring the struct has the right alignment.
fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> { fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
// This must produce the same result for `repr(transparent)` wrappers as for the inner type!
// In other words, this should generally not look at the type at all, but only at the
// layout.
if let Abi::Scalar(ref scalar) = self.abi { if let Abi::Scalar(ref scalar) = self.abi {
// Use a different cache for scalars because pointers to DSTs // Use a different cache for scalars because pointers to DSTs
// can be either fat or thin (data pointers of fat pointers). // can be either fat or thin (data pointers of fat pointers).
if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) { if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
return ty; return ty;
} }
let ty = let ty = self.scalar_gcc_type_at(cx, scalar, Size::ZERO);
match *self.ty.kind() {
ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
cx.type_ptr_to(cx.layout_of(ty).gcc_type(cx))
}
ty::Adt(def, _) if def.is_box() => {
cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).gcc_type(cx))
}
ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())),
_ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),
};
cx.scalar_types.borrow_mut().insert(self.ty, ty); cx.scalar_types.borrow_mut().insert(self.ty, ty);
return ty; return ty;
} }
@ -272,23 +265,10 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
} }
} }
fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc> { fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize) -> Type<'gcc> {
// TODO(antoyo): remove llvm hack: // This must produce the same result for `repr(transparent)` wrappers as for the inner type!
// HACK(eddyb) special-case fat pointers until LLVM removes // In other words, this should generally not look at the type at all, but only at the
// pointee types, to avoid bitcasting every `OperandRef::deref`. // layout.
match self.ty.kind() {
ty::Ref(..) | ty::RawPtr(_) => {
return self.field(cx, index).gcc_type(cx);
}
// only wide pointer boxes are handled as pointers
// thin pointer boxes with scalar allocators are handled by the general logic below
ty::Adt(def, args) if def.is_box() && cx.layout_of(args.type_at(1)).is_zst() => {
let ptr_ty = Ty::new_mut_ptr(cx.tcx,self.ty.boxed_ty());
return cx.layout_of(ptr_ty).scalar_pair_element_gcc_type(cx, index, immediate);
}
_ => {}
}
let (a, b) = match self.abi { let (a, b) = match self.abi {
Abi::ScalarPair(ref a, ref b) => (a, b), Abi::ScalarPair(ref a, ref b) => (a, b),
_ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self), _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self),
@ -367,8 +347,8 @@ impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
layout.gcc_field_index(index) layout.gcc_field_index(index)
} }
fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, immediate: bool) -> Type<'gcc> { fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, _immediate: bool) -> Type<'gcc> {
layout.scalar_pair_element_gcc_type(self, index, immediate) layout.scalar_pair_element_gcc_type(self, index)
} }
fn cast_backend_type(&self, ty: &CastTarget) -> Type<'gcc> { fn cast_backend_type(&self, ty: &CastTarget) -> Type<'gcc> {

View File

@ -571,7 +571,9 @@ impl From<Conv> for llvm::CallConv {
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall | Conv::RiscvInterrupt { .. } => { Conv::C | Conv::Rust | Conv::CCmseNonSecureCall | Conv::RiscvInterrupt { .. } => {
llvm::CCallConv llvm::CCallConv
} }
Conv::RustCold => llvm::ColdCallConv, Conv::Cold => llvm::ColdCallConv,
Conv::PreserveMost => llvm::PreserveMost,
Conv::PreserveAll => llvm::PreserveAll,
Conv::AmdGpuKernel => llvm::AmdGpuKernel, Conv::AmdGpuKernel => llvm::AmdGpuKernel,
Conv::AvrInterrupt => llvm::AvrInterrupt, Conv::AvrInterrupt => llvm::AvrInterrupt,
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,

View File

@ -20,7 +20,7 @@ pub fn compute_mir_scopes<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>, cx: &CodegenCx<'ll, 'tcx>,
instance: Instance<'tcx>, instance: Instance<'tcx>,
mir: &Body<'tcx>, mir: &Body<'tcx>,
debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>, debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
) { ) {
// Find all scopes with variables defined in them. // Find all scopes with variables defined in them.
let variables = if cx.sess().opts.debuginfo == DebugInfo::Full { let variables = if cx.sess().opts.debuginfo == DebugInfo::Full {
@ -51,7 +51,7 @@ fn make_mir_scope<'ll, 'tcx>(
instance: Instance<'tcx>, instance: Instance<'tcx>,
mir: &Body<'tcx>, mir: &Body<'tcx>,
variables: &Option<BitSet<SourceScope>>, variables: &Option<BitSet<SourceScope>>,
debug_context: &mut FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>, debug_context: &mut FunctionDebugContext<&'ll DIScope, &'ll DILocation>,
instantiated: &mut BitSet<SourceScope>, instantiated: &mut BitSet<SourceScope>,
scope: SourceScope, scope: SourceScope,
) { ) {
@ -84,6 +84,7 @@ fn make_mir_scope<'ll, 'tcx>(
} }
let loc = cx.lookup_debug_loc(scope_data.span.lo()); let loc = cx.lookup_debug_loc(scope_data.span.lo());
let file_metadata = file_metadata(cx, &loc.file);
let dbg_scope = match scope_data.inlined { let dbg_scope = match scope_data.inlined {
Some((callee, _)) => { Some((callee, _)) => {
@ -94,26 +95,18 @@ fn make_mir_scope<'ll, 'tcx>(
ty::ParamEnv::reveal_all(), ty::ParamEnv::reveal_all(),
ty::EarlyBinder::bind(callee), ty::EarlyBinder::bind(callee),
); );
debug_context.inlined_function_scopes.entry(callee).or_insert_with(|| { let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); cx.dbg_scope_fn(callee, callee_fn_abi, None)
cx.dbg_scope_fn(callee, callee_fn_abi, None)
})
}
None => {
let file_metadata = file_metadata(cx, &loc.file);
debug_context
.lexical_blocks
.entry((parent_scope.dbg_scope, loc.line, loc.col, file_metadata))
.or_insert_with(|| unsafe {
llvm::LLVMRustDIBuilderCreateLexicalBlock(
DIB(cx),
parent_scope.dbg_scope,
file_metadata,
loc.line,
loc.col,
)
})
} }
None => unsafe {
llvm::LLVMRustDIBuilderCreateLexicalBlock(
DIB(cx),
parent_scope.dbg_scope,
file_metadata,
loc.line,
loc.col,
)
},
}; };
let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { let inlined_at = scope_data.inlined.map(|(_, callsite_span)| {

View File

@ -5,7 +5,7 @@ use rustc_codegen_ssa::mir::debuginfo::VariableKind::*;
use self::metadata::{file_metadata, type_di_node}; use self::metadata::{file_metadata, type_di_node};
use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER}; use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER};
use self::namespace::mangled_name_of_instance; use self::namespace::mangled_name_of_instance;
use self::utils::{create_DIArray, debug_context, is_node_local_to_unit, DIB}; use self::utils::{create_DIArray, is_node_local_to_unit, DIB};
use crate::abi::FnAbi; use crate::abi::FnAbi;
use crate::builder::Builder; use crate::builder::Builder;
@ -67,8 +67,6 @@ pub struct CodegenUnitDebugContext<'ll, 'tcx> {
type_map: metadata::TypeMap<'ll, 'tcx>, type_map: metadata::TypeMap<'ll, 'tcx>,
namespace_map: RefCell<DefIdMap<&'ll DIScope>>, namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
recursion_marker_type: OnceCell<&'ll DIType>, recursion_marker_type: OnceCell<&'ll DIType>,
/// Maps a variable (name, scope, kind (argument or local), span) to its debug information.
variables: RefCell<FxHashMap<(Symbol, &'ll DIScope, VariableKind, Span), &'ll DIVariable>>,
} }
impl Drop for CodegenUnitDebugContext<'_, '_> { impl Drop for CodegenUnitDebugContext<'_, '_> {
@ -93,7 +91,6 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> {
type_map: Default::default(), type_map: Default::default(),
namespace_map: RefCell::new(Default::default()), namespace_map: RefCell::new(Default::default()),
recursion_marker_type: OnceCell::new(), recursion_marker_type: OnceCell::new(),
variables: RefCell::new(Default::default()),
} }
} }
@ -295,7 +292,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn_abi: &FnAbi<'tcx, Ty<'tcx>>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
llfn: &'ll Value, llfn: &'ll Value,
mir: &mir::Body<'tcx>, mir: &mir::Body<'tcx>,
) -> Option<FunctionDebugContext<'tcx, &'ll DIScope, &'ll DILocation>> { ) -> Option<FunctionDebugContext<&'ll DIScope, &'ll DILocation>> {
if self.sess().opts.debuginfo == DebugInfo::None { if self.sess().opts.debuginfo == DebugInfo::None {
return None; return None;
} }
@ -307,11 +304,8 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
file_start_pos: BytePos(0), file_start_pos: BytePos(0),
file_end_pos: BytePos(0), file_end_pos: BytePos(0),
}; };
let mut fn_debug_context = FunctionDebugContext { let mut fn_debug_context =
scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes), FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes) };
inlined_function_scopes: Default::default(),
lexical_blocks: Default::default(),
};
// Fill in all the scopes, with the information from the MIR body. // Fill in all the scopes, with the information from the MIR body.
compute_mir_scopes(self, instance, mir, &mut fn_debug_context); compute_mir_scopes(self, instance, mir, &mut fn_debug_context);
@ -612,39 +606,33 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
variable_kind: VariableKind, variable_kind: VariableKind,
span: Span, span: Span,
) -> &'ll DIVariable { ) -> &'ll DIVariable {
debug_context(self) let loc = self.lookup_debug_loc(span.lo());
.variables let file_metadata = file_metadata(self, &loc.file);
.borrow_mut()
.entry((variable_name, scope_metadata, variable_kind, span))
.or_insert_with(|| {
let loc = self.lookup_debug_loc(span.lo());
let file_metadata = file_metadata(self, &loc.file);
let type_metadata = type_di_node(self, variable_type); let type_metadata = type_di_node(self, variable_type);
let (argument_index, dwarf_tag) = match variable_kind { let (argument_index, dwarf_tag) = match variable_kind {
ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable), ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
LocalVariable => (0, DW_TAG_auto_variable), LocalVariable => (0, DW_TAG_auto_variable),
}; };
let align = self.align_of(variable_type); let align = self.align_of(variable_type);
let name = variable_name.as_str(); let name = variable_name.as_str();
unsafe { unsafe {
llvm::LLVMRustDIBuilderCreateVariable( llvm::LLVMRustDIBuilderCreateVariable(
DIB(self), DIB(self),
dwarf_tag, dwarf_tag,
scope_metadata, scope_metadata,
name.as_ptr().cast(), name.as_ptr().cast(),
name.len(), name.len(),
file_metadata, file_metadata,
loc.line, loc.line,
type_metadata, type_metadata,
true, true,
DIFlags::FlagZero, DIFlags::FlagZero,
argument_index, argument_index,
align.bytes() as u32, align.bytes() as u32,
) )
} }
})
} }
} }

View File

@ -83,12 +83,17 @@ pub enum LLVMModFlagBehavior {
// Consts for the LLVM CallConv type, pre-cast to usize. // Consts for the LLVM CallConv type, pre-cast to usize.
/// LLVM CallingConv::ID. Should we wrap this? /// LLVM CallingConv::ID. Should we wrap this?
///
/// See <https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/CallingConv.h>
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
#[repr(C)] #[repr(C)]
pub enum CallConv { pub enum CallConv {
CCallConv = 0, CCallConv = 0,
FastCallConv = 8, FastCallConv = 8,
ColdCallConv = 9, ColdCallConv = 9,
PreserveMost = 14,
PreserveAll = 15,
Tail = 18,
X86StdcallCallConv = 64, X86StdcallCallConv = 64,
X86FastcallCallConv = 65, X86FastcallCallConv = 65,
ArmAapcsCallConv = 67, ArmAapcsCallConv = 67,

View File

@ -3,7 +3,7 @@ use crate::context::TypeLowering;
use crate::type_::Type; use crate::type_::Type;
use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::traits::*;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use rustc_target::abi::HasDataLayout; use rustc_target::abi::HasDataLayout;
@ -215,20 +215,16 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
/// of that field's type - this is useful for taking the address of /// of that field's type - this is useful for taking the address of
/// that field and ensuring the struct has the right alignment. /// that field and ensuring the struct has the right alignment.
fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type { fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> &'a Type {
// This must produce the same result for `repr(transparent)` wrappers as for the inner type!
// In other words, this should generally not look at the type at all, but only at the
// layout.
if let Abi::Scalar(scalar) = self.abi { if let Abi::Scalar(scalar) = self.abi {
// Use a different cache for scalars because pointers to DSTs // Use a different cache for scalars because pointers to DSTs
// can be either fat or thin (data pointers of fat pointers). // can be either fat or thin (data pointers of fat pointers).
if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) {
return llty; return llty;
} }
let llty = match *self.ty.kind() { let llty = self.scalar_llvm_type_at(cx, scalar);
ty::Ref(..) | ty::RawPtr(_) => cx.type_ptr(),
ty::Adt(def, _) if def.is_box() => cx.type_ptr(),
ty::FnPtr(sig) => {
cx.fn_ptr_backend_type(cx.fn_abi_of_fn_ptr(sig, ty::List::empty()))
}
_ => self.scalar_llvm_type_at(cx, scalar),
};
cx.scalar_lltypes.borrow_mut().insert(self.ty, llty); cx.scalar_lltypes.borrow_mut().insert(self.ty, llty);
return llty; return llty;
} }
@ -303,27 +299,9 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
index: usize, index: usize,
immediate: bool, immediate: bool,
) -> &'a Type { ) -> &'a Type {
// HACK(eddyb) special-case fat pointers until LLVM removes // This must produce the same result for `repr(transparent)` wrappers as for the inner type!
// pointee types, to avoid bitcasting every `OperandRef::deref`. // In other words, this should generally not look at the type at all, but only at the
match *self.ty.kind() { // layout.
ty::Ref(..) | ty::RawPtr(_) => {
return self.field(cx, index).llvm_type(cx);
}
// only wide pointer boxes are handled as pointers
// thin pointer boxes with scalar allocators are handled by the general logic below
ty::Adt(def, args) if def.is_box() && cx.layout_of(args.type_at(1)).is_zst() => {
let ptr_ty = Ty::new_mut_ptr(cx.tcx, self.ty.boxed_ty());
return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
}
// `dyn* Trait` has the same ABI as `*mut dyn Trait`
ty::Dynamic(bounds, region, ty::DynStar) => {
let ptr_ty =
Ty::new_mut_ptr(cx.tcx, Ty::new_dynamic(cx.tcx, bounds, region, ty::Dyn));
return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
}
_ => {}
}
let Abi::ScalarPair(a, b) = self.abi else { let Abi::ScalarPair(a, b) = self.abi else {
bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self); bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self);
}; };
@ -405,7 +383,11 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
// Vectors, even for non-power-of-two sizes, have the same layout as // Vectors, even for non-power-of-two sizes, have the same layout as
// arrays but don't count as aggregate types // arrays but don't count as aggregate types
// While LLVM theoretically supports non-power-of-two sizes, and they
// often work fine, sometimes x86-isel deals with them horribly
// (see #115212) so for now only use power-of-two ones.
if let FieldsShape::Array { count, .. } = self.layout.fields() if let FieldsShape::Array { count, .. } = self.layout.fields()
&& count.is_power_of_two()
&& let element = self.field(cx, 0) && let element = self.field(cx, 0)
&& element.ty.is_integral() && element.ty.is_integral()
{ {

View File

@ -1,12 +1,10 @@
use crate::traits::*; use crate::traits::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::ty; use rustc_middle::ty;
use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::Instance;
use rustc_middle::ty::Ty; use rustc_middle::ty::Ty;
use rustc_session::config::DebugInfo; use rustc_session::config::DebugInfo;
use rustc_span::symbol::{kw, Symbol}; use rustc_span::symbol::{kw, Symbol};
@ -19,19 +17,11 @@ use super::{FunctionCx, LocalRef};
use std::ops::Range; use std::ops::Range;
pub struct FunctionDebugContext<'tcx, S, L> { pub struct FunctionDebugContext<S, L> {
/// Maps from source code to the corresponding debug info scope.
pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>, pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>,
/// Maps from a given inlined function to its debug info declaration.
pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>,
/// Maps from a lexical block (parent scope, line, column, file) to its debug info declaration.
/// This is particularily useful if the parent scope is an inlined function.
pub lexical_blocks: FxHashMap<(S, u32, u32, S), S>,
} }
#[derive(Copy, Clone, Eq, PartialEq, Hash)] #[derive(Copy, Clone)]
pub enum VariableKind { pub enum VariableKind {
ArgumentVariable(usize /*index*/), ArgumentVariable(usize /*index*/),
LocalVariable, LocalVariable,
@ -445,9 +435,23 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.store(place.llval, alloca.llval, alloca.align); bx.store(place.llval, alloca.llval, alloca.align);
// Point the debug info to `*alloca` for the current variable // Point the debug info to `*alloca` for the current variable
bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO], None); bx.dbg_var_addr(
dbg_var,
dbg_loc,
alloca.llval,
Size::ZERO,
&[Size::ZERO],
var.fragment,
);
} else { } else {
bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, &indirect_offsets, None); bx.dbg_var_addr(
dbg_var,
dbg_loc,
base.llval,
direct_offset,
&indirect_offsets,
var.fragment,
);
} }
} }
@ -570,17 +574,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
} }
let place = fragment.contents; let place = fragment.contents;
let fragment = if fragment_layout.size == Size::ZERO {
// Fragment is a ZST, so does not represent anything.
continue;
} else if fragment_layout.size == var_layout.size {
// Fragment covers entire variable, so as far as
// DWARF is concerned, it's not really a fragment.
None
} else {
Some(fragment_start..fragment_start + fragment_layout.size)
};
per_local[place.local].push(PerLocalVarDebugInfo { per_local[place.local].push(PerLocalVarDebugInfo {
name: var.name, name: var.name,
source_info: var.source_info, source_info: var.source_info,
dbg_var, dbg_var,
fragment: if fragment_layout.size == var_layout.size { fragment,
// Fragment covers entire variable, so as far as
// DWARF is concerned, it's not really a fragment.
None
} else {
Some(fragment_start..fragment_start + fragment_layout.size)
},
projection: place.projection, projection: place.projection,
}); });
} }

View File

@ -46,7 +46,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
mir: &'tcx mir::Body<'tcx>, mir: &'tcx mir::Body<'tcx>,
debug_context: Option<FunctionDebugContext<'tcx, Bx::DIScope, Bx::DILocation>>, debug_context: Option<FunctionDebugContext<Bx::DIScope, Bx::DILocation>>,
llfn: Bx::Function, llfn: Bx::Function,

View File

@ -26,7 +26,7 @@ pub trait DebugInfoMethods<'tcx>: BackendTypes {
fn_abi: &FnAbi<'tcx, Ty<'tcx>>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
llfn: Self::Function, llfn: Self::Function,
mir: &mir::Body<'tcx>, mir: &mir::Body<'tcx>,
) -> Option<FunctionDebugContext<'tcx, Self::DIScope, Self::DILocation>>; ) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>>;
// FIXME(eddyb) find a common convention for all of the debuginfo-related // FIXME(eddyb) find a common convention for all of the debuginfo-related
// names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.). // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).

View File

@ -255,6 +255,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
caller_abi: &ArgAbi<'tcx, Ty<'tcx>>, caller_abi: &ArgAbi<'tcx, Ty<'tcx>>,
callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, callee_abi: &ArgAbi<'tcx, Ty<'tcx>>,
) -> bool { ) -> bool {
let primitive_abi_compat = |a1: abi::Primitive, a2: abi::Primitive| -> bool {
match (a1, a2) {
// For integers, ignore the sign.
(abi::Primitive::Int(int_ty1, _sign1), abi::Primitive::Int(int_ty2, _sign2)) => {
int_ty1 == int_ty2
}
// For everything else we require full equality.
_ => a1 == a2,
}
};
// Heuristic for type comparison. // Heuristic for type comparison.
let layout_compat = || { let layout_compat = || {
if caller_abi.layout.ty == callee_abi.layout.ty { if caller_abi.layout.ty == callee_abi.layout.ty {
@ -267,28 +277,24 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// then who knows what happens. // then who knows what happens.
return false; return false;
} }
if caller_abi.layout.size != callee_abi.layout.size // This is tricky. Some ABIs split aggregates up into multiple registers etc, so we have
|| caller_abi.layout.align.abi != callee_abi.layout.align.abi // to be super careful here. For the scalar ABIs we conveniently already have all the
{ // newtypes unwrapped etc, so in those cases we can just compare the scalar components.
// This cannot go well... // Everything else we just reject for now.
return false;
}
// The rest *should* be okay, but we are extra conservative.
match (caller_abi.layout.abi, callee_abi.layout.abi) { match (caller_abi.layout.abi, callee_abi.layout.abi) {
// Different valid ranges are okay (once we enforce validity, // Different valid ranges are okay (the validity check will complain if this leads
// that will take care to make it UB to leave the range, just // to invalid transmutes).
// like for transmute).
(abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => { (abi::Abi::Scalar(caller), abi::Abi::Scalar(callee)) => {
caller.primitive() == callee.primitive() primitive_abi_compat(caller.primitive(), callee.primitive())
} }
( (
abi::Abi::ScalarPair(caller1, caller2), abi::Abi::ScalarPair(caller1, caller2),
abi::Abi::ScalarPair(callee1, callee2), abi::Abi::ScalarPair(callee1, callee2),
) => { ) => {
caller1.primitive() == callee1.primitive() primitive_abi_compat(caller1.primitive(), callee1.primitive())
&& caller2.primitive() == callee2.primitive() && primitive_abi_compat(caller2.primitive(), callee2.primitive())
} }
// Be conservative // Be conservative.
_ => false, _ => false,
} }
}; };
@ -309,7 +315,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
return true; return true;
}; };
let mode_compat = || match (&caller_abi.mode, &callee_abi.mode) { let mode_compat = || match (&caller_abi.mode, &callee_abi.mode) {
(PassMode::Ignore, PassMode::Ignore) => true, (PassMode::Ignore, PassMode::Ignore) => true, // can still be reached for the return type
(PassMode::Direct(a1), PassMode::Direct(a2)) => arg_attr_compat(a1, a2), (PassMode::Direct(a1), PassMode::Direct(a2)) => arg_attr_compat(a1, a2),
(PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => { (PassMode::Pair(a1, b1), PassMode::Pair(a2, b2)) => {
arg_attr_compat(a1, a2) && arg_attr_compat(b1, b2) arg_attr_compat(a1, a2) && arg_attr_compat(b1, b2)
@ -326,7 +332,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
_ => false, _ => false,
}; };
// We have to check both. `layout_compat` is needed to reject e.g. `i32` vs `f32`,
// which is not reflected in `PassMode`. `mode_compat` is needed to reject `u8` vs `bool`,
// which have the same `abi::Primitive` but different `arg_ext`.
if layout_compat() && mode_compat() { if layout_compat() && mode_compat() {
// Something went very wrong if our checks don't even imply that the layout is the same.
assert!(
caller_abi.layout.size == callee_abi.layout.size
&& caller_abi.layout.align.abi == callee_abi.layout.align.abi
);
return true; return true;
} }
trace!( trace!(

View File

@ -20,6 +20,8 @@ use rustc_mir_dataflow::{Analysis, ResultsCursor};
use rustc_target::abi::{Size, FIRST_VARIANT}; use rustc_target::abi::{Size, FIRST_VARIANT};
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use crate::util::is_within_packed;
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum EdgeKind { enum EdgeKind {
Unwind, Unwind,
@ -93,6 +95,7 @@ impl<'tcx> MirPass<'tcx> for Validator {
cfg_checker.visit_body(body); cfg_checker.visit_body(body);
cfg_checker.check_cleanup_control_flow(); cfg_checker.check_cleanup_control_flow();
// Also run the TypeChecker.
for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body) { for (location, msg) in validate_types(tcx, self.mir_phase, param_env, body) {
cfg_checker.fail(location, msg); cfg_checker.fail(location, msg);
} }
@ -427,14 +430,34 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
self.check_unwind_edge(location, *unwind); self.check_unwind_edge(location, *unwind);
// The call destination place and Operand::Move place used as an argument might be // The call destination place and Operand::Move place used as an argument might be
// passed by a reference to the callee. Consequently they must be non-overlapping. // passed by a reference to the callee. Consequently they must be non-overlapping
// Currently this simply checks for duplicate places. // and cannot be packed. Currently this simply checks for duplicate places.
self.place_cache.clear(); self.place_cache.clear();
self.place_cache.insert(destination.as_ref()); self.place_cache.insert(destination.as_ref());
if is_within_packed(self.tcx, &self.body.local_decls, *destination).is_some() {
// This is bad! The callee will expect the memory to be aligned.
self.fail(
location,
format!(
"encountered packed place in `Call` terminator destination: {:?}",
terminator.kind,
),
);
}
let mut has_duplicates = false; let mut has_duplicates = false;
for arg in args { for arg in args {
if let Operand::Move(place) = arg { if let Operand::Move(place) = arg {
has_duplicates |= !self.place_cache.insert(place.as_ref()); has_duplicates |= !self.place_cache.insert(place.as_ref());
if is_within_packed(self.tcx, &self.body.local_decls, *place).is_some() {
// This is bad! The callee will expect the memory to be aligned.
self.fail(
location,
format!(
"encountered `Move` of a packed place in `Call` terminator: {:?}",
terminator.kind,
),
);
}
} }
} }
@ -442,7 +465,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
self.fail( self.fail(
location, location,
format!( format!(
"encountered overlapping memory in `Call` terminator: {:?}", "encountered overlapping memory in `Move` arguments to `Call` terminator: {:?}",
terminator.kind, terminator.kind,
), ),
); );
@ -541,6 +564,8 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
} }
} }
/// A faster version of the validation pass that only checks those things which may break when apply
/// generic substitutions.
pub fn validate_types<'tcx>( pub fn validate_types<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
mir_phase: MirPhase, mir_phase: MirPhase,

View File

@ -34,6 +34,7 @@ where
false false
} }
_ => { _ => {
// We cannot figure out the layout. Conservatively assume that this is disaligned.
debug!("is_disaligned({:?}) - true", place); debug!("is_disaligned({:?}) - true", place);
true true
} }

View File

@ -20,7 +20,6 @@
//! the field `next_edge`). Each of those fields is an array that should //! the field `next_edge`). Each of those fields is an array that should
//! be indexed by the direction (see the type `Direction`). //! be indexed by the direction (see the type `Direction`).
use crate::snapshot_vec::{SnapshotVec, SnapshotVecDelegate};
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use std::fmt::Debug; use std::fmt::Debug;
@ -28,8 +27,8 @@ use std::fmt::Debug;
mod tests; mod tests;
pub struct Graph<N, E> { pub struct Graph<N, E> {
nodes: SnapshotVec<Node<N>>, nodes: Vec<Node<N>>,
edges: SnapshotVec<Edge<E>>, edges: Vec<Edge<E>>,
} }
pub struct Node<N> { pub struct Node<N> {
@ -45,20 +44,6 @@ pub struct Edge<E> {
pub data: E, pub data: E,
} }
impl<N> SnapshotVecDelegate for Node<N> {
type Value = Node<N>;
type Undo = ();
fn reverse(_: &mut Vec<Node<N>>, _: ()) {}
}
impl<N> SnapshotVecDelegate for Edge<N> {
type Value = Edge<N>;
type Undo = ();
fn reverse(_: &mut Vec<Edge<N>>, _: ()) {}
}
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
pub struct NodeIndex(pub usize); pub struct NodeIndex(pub usize);
@ -86,11 +71,11 @@ impl NodeIndex {
impl<N: Debug, E: Debug> Graph<N, E> { impl<N: Debug, E: Debug> Graph<N, E> {
pub fn new() -> Graph<N, E> { pub fn new() -> Graph<N, E> {
Graph { nodes: SnapshotVec::new(), edges: SnapshotVec::new() } Graph { nodes: Vec::new(), edges: Vec::new() }
} }
pub fn with_capacity(nodes: usize, edges: usize) -> Graph<N, E> { pub fn with_capacity(nodes: usize, edges: usize) -> Graph<N, E> {
Graph { nodes: SnapshotVec::with_capacity(nodes), edges: SnapshotVec::with_capacity(edges) } Graph { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) }
} }
// # Simple accessors // # Simple accessors

View File

@ -516,7 +516,8 @@ E0793: include_str!("./error_codes/E0793.md"),
E0794: include_str!("./error_codes/E0794.md"), E0794: include_str!("./error_codes/E0794.md"),
} }
// Undocumented removed error codes. Note that many removed error codes are documented. // Undocumented removed error codes. Note that many removed error codes are kept in the list above
// and marked as no-longer emitted with a note in the markdown file (see E0001 for an example).
// E0006, // merged with E0005 // E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard // E0008, // cannot bind by-move into a pattern guard
// E0019, // merged into E0015 // E0019, // merged into E0015

View File

@ -813,7 +813,9 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_variance_of_opaques, Normal, template!(Word), WarnFollowing),
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing), rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
rustc_attr!( rustc_attr!(
TEST, rustc_error, Normal, TEST, rustc_error, Normal,

View File

@ -56,6 +56,7 @@ pub fn provide(providers: &mut Providers) {
resolve_bound_vars::provide(providers); resolve_bound_vars::provide(providers);
*providers = Providers { *providers = Providers {
type_of: type_of::type_of, type_of: type_of::type_of,
type_of_opaque: type_of::type_of_opaque,
item_bounds: item_bounds::item_bounds, item_bounds: item_bounds::item_bounds,
explicit_item_bounds: item_bounds::explicit_item_bounds, explicit_item_bounds: item_bounds::explicit_item_bounds,
generics_of: generics_of::generics_of, generics_of: generics_of::generics_of,

View File

@ -1,7 +1,8 @@
use rustc_errors::{Applicability, StashKey}; use rustc_errors::{Applicability, StashKey};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::HirId; use rustc_hir::HirId;
use rustc_middle::query::plumbing::CyclePlaceholder;
use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
@ -388,86 +389,62 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
} }
}, },
Node::Item(item) => { Node::Item(item) => match item.kind {
match item.kind { ItemKind::Static(ty, .., body_id) => {
ItemKind::Static(ty, .., body_id) => { if is_suggestable_infer_ty(ty) {
if is_suggestable_infer_ty(ty) { infer_placeholder_type(
infer_placeholder_type( tcx,
tcx, def_id,
def_id, body_id,
body_id, ty.span,
ty.span, item.ident,
item.ident, "static variable",
"static variable", )
) } else {
} else { icx.to_ty(ty)
icx.to_ty(ty)
}
}
ItemKind::Const(ty, _, body_id) => {
if is_suggestable_infer_ty(ty) {
infer_placeholder_type(
tcx, def_id, body_id, ty.span, item.ident, "constant",
)
} else {
icx.to_ty(ty)
}
}
ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
spans if spans.len() > 0 => {
let guar = tcx.sess.emit_err(crate::errors::SelfInImplSelf {
span: spans.into(),
note: (),
});
Ty::new_error(tcx, guar)
}
_ => icx.to_ty(*self_ty),
},
ItemKind::Fn(..) => {
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
}
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
let def = tcx.adt_def(def_id);
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_adt(tcx, def, args)
}
ItemKind::OpaqueTy(OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { .. },
..
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(&OpaqueTy {
origin:
hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
in_trait,
..
}) => {
if in_trait && !tcx.defaultness(owner).has_value() {
span_bug!(
tcx.def_span(def_id),
"tried to get type of this RPITIT with no definition"
);
}
opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
}
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
| ItemKind::Macro(..)
| ItemKind::Mod(..)
| ItemKind::ForeignMod { .. }
| ItemKind::GlobalAsm(..)
| ItemKind::ExternCrate(..)
| ItemKind::Use(..) => {
span_bug!(
item.span,
"compute_type_of_item: unexpected item type: {:?}",
item.kind
);
} }
} }
} ItemKind::Const(ty, _, body_id) => {
if is_suggestable_infer_ty(ty) {
infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
} else {
icx.to_ty(ty)
}
}
ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
spans if spans.len() > 0 => {
let guar = tcx
.sess
.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
Ty::new_error(tcx, guar)
}
_ => icx.to_ty(*self_ty),
},
ItemKind::Fn(..) => {
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_fn_def(tcx, def_id.to_def_id(), args)
}
ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
let def = tcx.adt_def(def_id);
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
Ty::new_adt(tcx, def, args)
}
ItemKind::OpaqueTy(..) => tcx.type_of_opaque(def_id).map_or_else(
|CyclePlaceholder(guar)| Ty::new_error(tcx, guar),
|ty| ty.instantiate_identity(),
),
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
| ItemKind::Macro(..)
| ItemKind::Mod(..)
| ItemKind::ForeignMod { .. }
| ItemKind::GlobalAsm(..)
| ItemKind::ExternCrate(..)
| ItemKind::Use(..) => {
span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind);
}
},
Node::ForeignItem(foreign_item) => match foreign_item.kind { Node::ForeignItem(foreign_item) => match foreign_item.kind {
ForeignItemKind::Fn(..) => { ForeignItemKind::Fn(..) => {
@ -514,6 +491,51 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
ty::EarlyBinder::bind(output) ty::EarlyBinder::bind(output)
} }
pub(super) fn type_of_opaque(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
if let Some(def_id) = def_id.as_local() {
use rustc_hir::*;
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
Ok(ty::EarlyBinder::bind(match tcx.hir().get(hir_id) {
Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias { .. },
..
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(&OpaqueTy {
origin:
hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner),
in_trait,
..
}) => {
if in_trait && !tcx.defaultness(owner).has_value() {
span_bug!(
tcx.def_span(def_id),
"tried to get type of this RPITIT with no definition"
);
}
opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
}
_ => {
span_bug!(item.span, "type_of_opaque: unexpected item type: {:?}", item.kind);
}
},
x => {
bug!("unexpected sort of node in type_of_opaque(): {:?}", x);
}
}))
} else {
// Foreign opaque type will go through the foreign provider
// and load the type from metadata.
Ok(tcx.type_of(def_id))
}
}
fn infer_placeholder_type<'a>( fn infer_placeholder_type<'a>(
tcx: TyCtxt<'a>, tcx: TyCtxt<'a>,
def_id: LocalDefId, def_id: LocalDefId,

View File

@ -1,9 +1,24 @@
use rustc_hir::def::DefKind;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use crate::errors; use crate::errors;
pub fn test_variance(tcx: TyCtxt<'_>) { pub fn test_variance(tcx: TyCtxt<'_>) {
if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) {
for id in tcx.hir().items() {
if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
let variances_of = tcx.variances_of(id.owner_id);
tcx.sess.emit_err(errors::VariancesOf {
span: tcx.def_span(id.owner_id),
variances_of: format!("{variances_of:?}"),
});
}
}
}
// For unit testing: check for a special "rustc_variance" // For unit testing: check for a special "rustc_variance"
// attribute and report an error with various results if found. // attribute and report an error with various results if found.
for id in tcx.hir().items() { for id in tcx.hir().items() {

View File

@ -231,7 +231,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let inferred_sig = self.normalize( let inferred_sig = self.normalize(
span, span,
self.deduce_sig_from_projection( self.deduce_sig_from_projection(
Some(span), Some(span),
bound_predicate.rebind(proj_predicate), bound_predicate.rebind(proj_predicate),
), ),
); );

View File

@ -20,10 +20,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
else { else {
return false; return false;
}; };
let hir = self.tcx.hir();
let hir::Node::Expr(expr) = hir.get(hir_id) else {
return false;
};
let Some(unsubstituted_pred) = self let Some(unsubstituted_pred) = self
.tcx .tcx
@ -47,6 +43,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => return false, _ => return false,
}; };
let direct_param = if let ty::ClauseKind::Trait(pred) = unsubstituted_pred.kind().skip_binder()
&& let ty = pred.trait_ref.self_ty()
&& let ty::Param(_param) = ty.kind()
&& let Some(arg) = predicate_args.get(0)
&& let ty::GenericArgKind::Type(arg_ty) = arg.unpack()
&& arg_ty == ty
{
Some(*arg)
} else {
None
};
let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| { let find_param_matching = |matches: &dyn Fn(ty::ParamTerm) -> bool| {
predicate_args.iter().find_map(|arg| { predicate_args.iter().find_map(|arg| {
arg.walk().find_map(|arg| { arg.walk().find_map(|arg| {
@ -96,54 +103,83 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate); self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
} }
if self.closure_span_overlaps_error(error, expr.span) { let hir = self.tcx.hir();
return false; let (expr, qpath) = match hir.get(hir_id) {
} hir::Node::Expr(expr) => {
if self.closure_span_overlaps_error(error, expr.span) {
return false;
}
let qpath =
if let hir::ExprKind::Path(qpath) = expr.kind { Some(qpath) } else { None };
match &expr.kind { (Some(*expr), qpath)
hir::ExprKind::Path(qpath) => { }
if let hir::Node::Expr(hir::Expr { hir::Node::Ty(hir::Ty { kind: hir::TyKind::Path(qpath), .. }) => (None, Some(*qpath)),
kind: hir::ExprKind::Call(callee, args), _ => return false,
hir_id: call_hir_id, };
span: call_span,
..
}) = hir.get_parent(expr.hir_id)
&& callee.hir_id == expr.hir_id
{
if self.closure_span_overlaps_error(error, *call_span) {
return false;
}
for param in if let Some(qpath) = qpath {
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] if let Some(param) = direct_param {
.into_iter() if self.point_at_path_if_possible(error, def_id, param, &qpath) {
.flatten() return true;
{ }
if self.blame_specific_arg_if_possible( }
error, if let hir::Node::Expr(hir::Expr {
def_id, kind: hir::ExprKind::Call(callee, args),
param, hir_id: call_hir_id,
*call_hir_id, span: call_span,
callee.span, ..
None, }) = hir.get_parent(hir_id)
args, && callee.hir_id == hir_id
) {
{ if self.closure_span_overlaps_error(error, *call_span) {
return true; return false;
}
}
} }
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] for param in
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter() .into_iter()
.flatten() .flatten()
{ {
if self.point_at_path_if_possible(error, def_id, param, qpath) { if self.blame_specific_arg_if_possible(
error,
def_id,
param,
*call_hir_id,
callee.span,
None,
args,
)
{
return true; return true;
} }
} }
} }
hir::ExprKind::MethodCall(segment, receiver, args, ..) => {
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter()
.flatten()
{
if self.point_at_path_if_possible(error, def_id, param, &qpath) {
return true;
}
}
}
match expr.map(|e| e.kind) {
Some(hir::ExprKind::MethodCall(segment, receiver, args, ..)) => {
if let Some(param) = direct_param
&& self.point_at_generic_if_possible(error, def_id, param, segment)
{
error.obligation.cause.map_code(|parent_code| {
ObligationCauseCode::FunctionArgumentObligation {
arg_hir_id: receiver.hir_id,
call_hir_id: hir_id,
parent_code,
}
});
return true;
}
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
.into_iter() .into_iter()
.flatten() .flatten()
@ -175,7 +211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return true; return true;
} }
} }
hir::ExprKind::Struct(qpath, fields, ..) => { Some(hir::ExprKind::Struct(qpath, fields, ..)) => {
if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) = if let Res::Def(DefKind::Struct | DefKind::Variant, variant_def_id) =
self.typeck_results.borrow().qpath_res(qpath, hir_id) self.typeck_results.borrow().qpath_res(qpath, hir_id)
{ {
@ -200,9 +236,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
for param in [param_to_point_at, fallback_param_to_point_at, self_param_to_point_at] for param in [
.into_iter() direct_param,
.flatten() param_to_point_at,
fallback_param_to_point_at,
self_param_to_point_at,
]
.into_iter()
.flatten()
{ {
if self.point_at_path_if_possible(error, def_id, param, qpath) { if self.point_at_path_if_possible(error, def_id, param, qpath) {
return true; return true;
@ -434,7 +475,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
/** /**
* Recursively searches for the most-specific blamable expression. * Recursively searches for the most-specific blameable expression.
* For example, if you have a chain of constraints like: * For example, if you have a chain of constraints like:
* - want `Vec<i32>: Copy` * - want `Vec<i32>: Copy`
* - because `Option<Vec<i32>>: Copy` needs `Vec<i32>: Copy` because `impl <T: Copy> Copy for Option<T>` * - because `Option<Vec<i32>>: Copy` needs `Vec<i32>: Copy` because `impl <T: Copy> Copy for Option<T>`

View File

@ -317,7 +317,18 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) { fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
// FIXME: normalization and escaping regions // FIXME: normalization and escaping regions
let ty = if !ty.has_escaping_bound_vars() { self.normalize(span, ty) } else { ty }; let ty = if !ty.has_escaping_bound_vars() {
if let ty::Alias(
ty::AliasKind::Projection | ty::AliasKind::Weak,
ty::AliasTy { args, def_id, .. },
) = ty.kind()
{
self.add_required_obligations_for_hir(span, *def_id, args, hir_id);
}
self.normalize(span, ty)
} else {
ty
};
self.write_ty(hir_id, ty) self.write_ty(hir_id, ty)
} }

View File

@ -15,7 +15,6 @@ use rustc_data_structures::graph::implementation::{
use rustc_data_structures::intern::Interned; use rustc_data_structures::intern::Interned;
use rustc_index::{IndexSlice, IndexVec}; use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::PlaceholderRegion;
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReEarlyBound, ReErased, ReError, ReFree, ReStatic}; use rustc_middle::ty::{ReEarlyBound, ReErased, ReError, ReFree, ReStatic};
use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar}; use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
@ -173,38 +172,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
} }
} }
/// Gets the LUb of a given region and the empty region
fn lub_empty(&self, a_region: Region<'tcx>) -> Result<Region<'tcx>, PlaceholderRegion> {
match *a_region {
ReLateBound(..) | ReErased => {
bug!("cannot relate region: {:?}", a_region);
}
ReVar(v_id) => {
span_bug!(
self.var_infos[v_id].origin.span(),
"lub invoked with non-concrete regions: {:?}",
a_region,
);
}
ReStatic => {
// nothing lives longer than `'static`
Ok(self.tcx().lifetimes.re_static)
}
ReError(_) => Ok(a_region),
ReEarlyBound(_) | ReFree(_) => {
// All empty regions are less than early-bound, free,
// and scope regions.
Ok(a_region)
}
RePlaceholder(placeholder) => Err(placeholder),
}
}
fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) { fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
// In the first pass, we expand region vids according to constraints we // In the first pass, we expand region vids according to constraints we
// have previously found. In the second pass, we loop through the region // have previously found. In the second pass, we loop through the region
@ -247,27 +214,25 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
true true
} }
VarValue::Value(cur_region) => { VarValue::Value(cur_region) => {
let lub = match self.lub_empty(cur_region) { match *cur_region {
Ok(r) => r, // If this empty region is from a universe that can name the
// If the empty and placeholder regions are in the same universe, // placeholder universe, then the LUB is the Placeholder region
// then the LUB is the Placeholder region (which is the cur_region). // (which is the cur_region). Otherwise, the LUB is the Static
// If they are not in the same universe, the LUB is the Static lifetime. // lifetime.
Err(placeholder) if a_universe == placeholder.universe => { RePlaceholder(placeholder)
cur_region if !a_universe.can_name(placeholder.universe) =>
{
let lub = self.tcx().lifetimes.re_static;
debug!(
"Expanding value of {:?} from {:?} to {:?}",
b_vid, cur_region, lub
);
*b_data = VarValue::Value(lub);
true
} }
Err(_) => self.tcx().lifetimes.re_static,
};
if lub == cur_region { _ => false,
false
} else {
debug!(
"Expanding value of {:?} from {:?} to {:?}",
b_vid, cur_region, lub
);
*b_data = VarValue::Value(lub);
true
} }
} }
@ -341,15 +306,19 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
match *b_data { match *b_data {
VarValue::Empty(empty_ui) => { VarValue::Empty(empty_ui) => {
let lub = match self.lub_empty(a_region) { let lub = match *a_region {
Ok(r) => r, RePlaceholder(placeholder) => {
// If this empty region is from a universe that can // If this empty region is from a universe that can
// name the placeholder, then the placeholder is // name the placeholder, then the placeholder is
// larger; otherwise, the only ancestor is `'static`. // larger; otherwise, the only ancestor is `'static`.
Err(placeholder) if empty_ui.can_name(placeholder.universe) => { if empty_ui.can_name(placeholder.universe) {
ty::Region::new_placeholder(self.tcx(), placeholder) ty::Region::new_placeholder(self.tcx(), placeholder)
} else {
self.tcx().lifetimes.re_static
}
} }
Err(_) => self.tcx().lifetimes.re_static,
_ => a_region,
}; };
debug!("Expanding value of {:?} from empty lifetime to {:?}", b_vid, lub); debug!("Expanding value of {:?} from empty lifetime to {:?}", b_vid, lub);

View File

@ -22,7 +22,7 @@ use rustc_middle::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
use rustc_mir_build as mir_build; use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
use rustc_passes::{self, hir_stats, layout_test}; use rustc_passes::{self, abi_test, hir_stats, layout_test};
use rustc_plugin_impl as plugin; use rustc_plugin_impl as plugin;
use rustc_resolve::Resolver; use rustc_resolve::Resolver;
use rustc_session::code_stats::VTableSizeInfo; use rustc_session::code_stats::VTableSizeInfo;
@ -818,6 +818,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
} }
sess.time("layout_testing", || layout_test::test_layout(tcx)); sess.time("layout_testing", || layout_test::test_layout(tcx));
sess.time("abi_testing", || abi_test::test_abi(tcx));
// Avoid overwhelming user with errors if borrow checking failed. // Avoid overwhelming user with errors if borrow checking failed.
// I'm not sure how helpful this is, to be honest, but it avoids a // I'm not sure how helpful this is, to be honest, but it avoids a

View File

@ -807,6 +807,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(no_jump_tables, true); tracked!(no_jump_tables, true);
tracked!(no_link, true); tracked!(no_link, true);
tracked!(no_profiler_runtime, true); tracked!(no_profiler_runtime, true);
tracked!(no_trait_vptr, true);
tracked!(no_unique_section_names, true); tracked!(no_unique_section_names, true);
tracked!(oom, OomStrategy::Panic); tracked!(oom, OomStrategy::Panic);
tracked!(osx_rpath_install_name, true); tracked!(osx_rpath_install_name, true);
@ -821,7 +822,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(profile_emit, Some(PathBuf::from("abc"))); tracked!(profile_emit, Some(PathBuf::from("abc")));
tracked!(profile_sample_use, Some(PathBuf::from("abc"))); tracked!(profile_sample_use, Some(PathBuf::from("abc")));
tracked!(profiler_runtime, "abc".to_string()); tracked!(profiler_runtime, "abc".to_string());
tracked!(relax_elf_relocations, Some(false)); tracked!(relax_elf_relocations, Some(true));
tracked!(relro_level, Some(RelroLevel::Full)); tracked!(relro_level, Some(RelroLevel::Full));
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc"))); tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
tracked!(report_delayed_bugs, true); tracked!(report_delayed_bugs, true);

View File

@ -321,13 +321,13 @@ extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM,
PrintBackendInfo Print, PrintBackendInfo Print,
void* Out) { void* Out) {
const TargetMachine *Target = unwrap(TM); const TargetMachine *Target = unwrap(TM);
const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
const Triple::ArchType HostArch = Triple(sys::getDefaultTargetTriple()).getArch(); const Triple::ArchType HostArch = Triple(sys::getDefaultTargetTriple()).getArch();
const Triple::ArchType TargetArch = Target->getTargetTriple().getArch(); const Triple::ArchType TargetArch = Target->getTargetTriple().getArch();
std::ostringstream Buf; std::ostringstream Buf;
#if LLVM_VERSION_GE(17, 0) #if LLVM_VERSION_GE(17, 0)
const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getAllProcessorDescriptions(); const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getAllProcessorDescriptions();
#else #else
Buf << "Full target CPU help is not supported by this LLVM version.\n\n"; Buf << "Full target CPU help is not supported by this LLVM version.\n\n";

View File

@ -347,6 +347,13 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for Symbol {
} }
} }
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for [u8] {
fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) {
Encoder::emit_usize(e, self.len());
e.emit_raw_bytes(self);
}
}
impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> { impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> {
const CLEAR_CROSS_CRATE: bool = true; const CLEAR_CROSS_CRATE: bool = true;

View File

@ -1,4 +1,5 @@
use crate::mir; use crate::mir;
use crate::query::CyclePlaceholder;
use crate::traits; use crate::traits;
use crate::ty::{self, Ty}; use crate::ty::{self, Ty};
use std::mem::{size_of, transmute_copy, MaybeUninit}; use std::mem::{size_of, transmute_copy, MaybeUninit};
@ -142,6 +143,10 @@ impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
[u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()]; [u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()];
} }
impl EraseType for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
type Result = [u8; size_of::<Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder>>()];
}
impl<T> EraseType for Option<&'_ T> { impl<T> EraseType for Option<&'_ T> {
type Result = [u8; size_of::<Option<&'static ()>>()]; type Result = [u8; size_of::<Option<&'static ()>>()];
} }

View File

@ -26,7 +26,7 @@ use crate::mir::interpret::{
use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::interpret::{LitToConstError, LitToConstInput};
use crate::mir::mono::CodegenUnit; use crate::mir::mono::CodegenUnit;
use crate::query::erase::{erase, restore, Erase}; use crate::query::erase::{erase, restore, Erase};
use crate::query::plumbing::{query_ensure, query_get_at, DynamicQuery}; use crate::query::plumbing::{query_ensure, query_get_at, CyclePlaceholder, DynamicQuery};
use crate::thir; use crate::thir;
use crate::traits::query::{ use crate::traits::query::{
CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
@ -243,6 +243,16 @@ rustc_queries! {
feedable feedable
} }
/// Specialized instance of `type_of` that detects cycles that are due to
/// revealing opaque because of an auto trait bound. Unless `CyclePlaceholder` needs
/// to be handled separately, call `type_of` instead.
query type_of_opaque(key: DefId) -> Result<ty::EarlyBinder<Ty<'tcx>>, CyclePlaceholder> {
desc { |tcx|
"computing type of opaque `{path}`",
path = tcx.def_path_str(key),
}
}
query collect_return_position_impl_trait_in_trait_tys(key: DefId) query collect_return_position_impl_trait_in_trait_tys(key: DefId)
-> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed>
{ {

View File

@ -19,7 +19,7 @@ use rustc_query_system::dep_graph::SerializedDepNodeIndex;
pub(crate) use rustc_query_system::query::QueryJobId; pub(crate) use rustc_query_system::query::QueryJobId;
use rustc_query_system::query::*; use rustc_query_system::query::*;
use rustc_query_system::HandleCycleError; use rustc_query_system::HandleCycleError;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
use std::ops::Deref; use std::ops::Deref;
pub struct QueryKeyStringCache { pub struct QueryKeyStringCache {
@ -52,7 +52,8 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
pub loadable_from_disk: pub loadable_from_disk:
fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool, fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,
pub hash_result: HashResult<C::Value>, pub hash_result: HashResult<C::Value>,
pub value_from_cycle_error: fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> C::Value, pub value_from_cycle_error:
fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>], guar: ErrorGuaranteed) -> C::Value,
pub format_value: fn(&C::Value) -> String, pub format_value: fn(&C::Value) -> String,
} }
@ -629,3 +630,6 @@ impl<'tcx> TyCtxtAt<'tcx> {
.unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id)) .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
} }
} }
#[derive(Copy, Clone, Debug, HashStable)]
pub struct CyclePlaceholder(pub ErrorGuaranteed);

View File

@ -1,4 +1,5 @@
use crate::dep_graph::DepKind; use crate::dep_graph::DepKind;
use crate::query::plumbing::CyclePlaceholder;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan}; use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
use rustc_hir as hir; use rustc_hir as hir;
@ -8,20 +9,38 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_query_system::query::QueryInfo; use rustc_query_system::query::QueryInfo;
use rustc_query_system::Value; use rustc_query_system::Value;
use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LocalDefId;
use rustc_span::Span; use rustc_span::{ErrorGuaranteed, Span};
use std::fmt::Write; use std::fmt::Write;
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> { impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self { fn from_cycle_error(
tcx: TyCtxt<'tcx>,
_: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self {
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`. // SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow. // FIXME: Represent the above fact in the trait system somehow.
unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_misc_error(tcx)) } unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_error(tcx, guar)) }
}
}
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
fn from_cycle_error(
_tcx: TyCtxt<'tcx>,
_: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self {
Err(CyclePlaceholder(guar))
} }
} }
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> { impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self { fn from_cycle_error(
tcx: TyCtxt<'tcx>,
_: &[QueryInfo<DepKind>],
_guar: ErrorGuaranteed,
) -> Self {
// SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`. // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
// FIXME: Represent the above fact in the trait system somehow. // FIXME: Represent the above fact in the trait system somehow.
unsafe { unsafe {
@ -33,8 +52,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
} }
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> { impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo<DepKind>]) -> Self { fn from_cycle_error(
let err = Ty::new_misc_error(tcx); tcx: TyCtxt<'tcx>,
stack: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self {
let err = Ty::new_error(tcx, guar);
let arity = if let Some(frame) = stack.get(0) let arity = if let Some(frame) = stack.get(0)
&& frame.query.dep_kind == DepKind::fn_sig && frame.query.dep_kind == DepKind::fn_sig
@ -63,7 +86,11 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
} }
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability { impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self { fn from_cycle_error(
tcx: TyCtxt<'tcx>,
cycle: &[QueryInfo<DepKind>],
_guar: ErrorGuaranteed,
) -> Self {
let mut item_and_field_ids = Vec::new(); let mut item_and_field_ids = Vec::new();
let mut representable_ids = FxHashSet::default(); let mut representable_ids = FxHashSet::default();
for info in cycle { for info in cycle {
@ -95,22 +122,35 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
} }
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> { impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self { fn from_cycle_error(
ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle)) tcx: TyCtxt<'tcx>,
cycle: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self {
ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle, guar))
} }
} }
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> { impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self { fn from_cycle_error(
ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle)) tcx: TyCtxt<'tcx>,
cycle: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self {
ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle, guar))
} }
} }
impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> { impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> {
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self { fn from_cycle_error(
_tcx: TyCtxt<'tcx>,
_cycle: &[QueryInfo<DepKind>],
_guar: ErrorGuaranteed,
) -> Self {
// tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
// min_specialization. Since this is an error path anyways, leaking doesn't matter (and really, // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,
// tcx.arena.alloc is pretty much equal to leaking). // tcx.arena.alloc is pretty much equal to leaking).
// FIXME: `Cycle` should carry the ErrorGuaranteed
Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle))) Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle)))
} }
} }

View File

@ -590,6 +590,8 @@ struct MirUsedCollector<'a, 'tcx> {
body: &'a mir::Body<'tcx>, body: &'a mir::Body<'tcx>,
output: &'a mut MonoItems<'tcx>, output: &'a mut MonoItems<'tcx>,
instance: Instance<'tcx>, instance: Instance<'tcx>,
/// Spans for move size lints already emitted. Helps avoid duplicate lints.
move_size_spans: Vec<Span>,
} }
impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> { impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
@ -604,6 +606,45 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
ty::EarlyBinder::bind(value), ty::EarlyBinder::bind(value),
) )
} }
fn check_move_size(&mut self, limit: usize, operand: &mir::Operand<'tcx>, location: Location) {
let limit = Size::from_bytes(limit);
let ty = operand.ty(self.body, self.tcx);
let ty = self.monomorphize(ty);
let Ok(layout) = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) else { return };
if layout.size <= limit {
return;
}
debug!(?layout);
let source_info = self.body.source_info(location);
debug!(?source_info);
for span in &self.move_size_spans {
if span.overlaps(source_info.span) {
return;
}
}
let lint_root = source_info.scope.lint_root(&self.body.source_scopes);
debug!(?lint_root);
let Some(lint_root) = lint_root else {
// This happens when the issue is in a function from a foreign crate that
// we monomorphized in the current crate. We can't get a `HirId` for things
// in other crates.
// FIXME: Find out where to report the lint on. Maybe simply crate-level lint root
// but correct span? This would make the lint at least accept crate-level lint attributes.
return;
};
self.tcx.emit_spanned_lint(
LARGE_ASSIGNMENTS,
lint_root,
source_info.span,
LargeAssignmentsLint {
span: source_info.span,
size: layout.size.bytes(),
limit: limit.bytes(),
},
);
self.move_size_spans.push(source_info.span);
}
} }
impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
@ -803,40 +844,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) { fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
self.super_operand(operand, location); self.super_operand(operand, location);
let limit = self.tcx.move_size_limit().0; let move_size_limit = self.tcx.move_size_limit().0;
if limit == 0 { if move_size_limit > 0 {
return; self.check_move_size(move_size_limit, operand, location);
}
let limit = Size::from_bytes(limit);
let ty = operand.ty(self.body, self.tcx);
let ty = self.monomorphize(ty);
let layout = self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty));
if let Ok(layout) = layout {
if layout.size > limit {
debug!(?layout);
let source_info = self.body.source_info(location);
debug!(?source_info);
let lint_root = source_info.scope.lint_root(&self.body.source_scopes);
debug!(?lint_root);
let Some(lint_root) = lint_root else {
// This happens when the issue is in a function from a foreign crate that
// we monomorphized in the current crate. We can't get a `HirId` for things
// in other crates.
// FIXME: Find out where to report the lint on. Maybe simply crate-level lint root
// but correct span? This would make the lint at least accept crate-level lint attributes.
return;
};
self.tcx.emit_spanned_lint(
LARGE_ASSIGNMENTS,
lint_root,
source_info.span,
LargeAssignmentsLint {
span: source_info.span,
size: layout.size.bytes(),
limit: limit.bytes(),
},
)
}
} }
} }
@ -1363,7 +1373,8 @@ fn collect_used_items<'tcx>(
output: &mut MonoItems<'tcx>, output: &mut MonoItems<'tcx>,
) { ) {
let body = tcx.instance_mir(instance.def); let body = tcx.instance_mir(instance.def);
MirUsedCollector { tcx, body: &body, output, instance }.visit_body(&body); MirUsedCollector { tcx, body: &body, output, instance, move_size_spans: vec![] }
.visit_body(&body);
} }
#[instrument(skip(tcx, output), level = "debug")] #[instrument(skip(tcx, output), level = "debug")]

View File

@ -7,6 +7,9 @@
passes_abi = passes_abi =
abi: {$abi} abi: {$abi}
passes_abi_of =
fn_abi_of_instance({$fn_name}) = {$fn_abi}
passes_align = passes_align =
align: {$align} align: {$align}

View File

@ -0,0 +1,93 @@
use rustc_ast::Attribute;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::layout::{FnAbiError, LayoutError};
use rustc_middle::ty::{self, GenericArgs, Instance, TyCtxt};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
use crate::errors::{AbiOf, UnrecognizedField};
pub fn test_abi(tcx: TyCtxt<'_>) {
if !tcx.features().rustc_attrs {
// if the `rustc_attrs` feature is not enabled, don't bother testing ABI
return;
}
for id in tcx.hir().items() {
match tcx.def_kind(id.owner_id) {
DefKind::Fn => {
for attr in tcx.get_attrs(id.owner_id, sym::rustc_abi) {
dump_abi_of(tcx, id.owner_id.def_id.into(), attr);
}
}
DefKind::Impl { .. } => {
// To find associated functions we need to go into the child items here.
for &id in tcx.associated_item_def_ids(id.owner_id) {
if matches!(tcx.def_kind(id), DefKind::AssocFn) {
for attr in tcx.get_attrs(id, sym::rustc_abi) {
dump_abi_of(tcx, id, attr);
}
}
}
}
_ => {}
}
}
}
fn dump_abi_of(tcx: TyCtxt<'_>, item_def_id: DefId, attr: &Attribute) {
let param_env = tcx.param_env(item_def_id);
let args = GenericArgs::identity_for_item(tcx, item_def_id);
let instance = match Instance::resolve(tcx, param_env, item_def_id, args) {
Ok(Some(instance)) => instance,
Ok(None) => {
// Not sure what to do here, but `LayoutError::Unknown` seems reasonable?
let ty = tcx.type_of(item_def_id).instantiate_identity();
tcx.sess.emit_fatal(Spanned {
node: LayoutError::Unknown(ty).into_diagnostic(),
span: tcx.def_span(item_def_id),
});
}
Err(_guaranteed) => return,
};
match tcx.fn_abi_of_instance(param_env.and((instance, /* extra_args */ ty::List::empty()))) {
Ok(abi) => {
// Check out the `#[rustc_abi(..)]` attribute to tell what to dump.
// The `..` are the names of fields to dump.
let meta_items = attr.meta_item_list().unwrap_or_default();
for meta_item in meta_items {
match meta_item.name_or_empty() {
sym::debug => {
let fn_name = tcx.item_name(item_def_id);
tcx.sess.emit_err(AbiOf {
span: tcx.def_span(item_def_id),
fn_name,
fn_abi: format!("{:#?}", abi),
});
}
name => {
tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
}
}
}
}
Err(FnAbiError::Layout(layout_error)) => {
tcx.sess.emit_fatal(Spanned {
node: layout_error.into_diagnostic(),
span: tcx.def_span(item_def_id),
});
}
Err(FnAbiError::AdjustForForeignAbi(e)) => {
// Sadly there seems to be no `into_diagnostic` for this case... and I am not sure if
// this can even be reached. Anyway this is a perma-unstable debug attribute, an ICE
// isn't the worst thing. Also this matches what codegen does.
span_bug!(
tcx.def_span(item_def_id),
"error computing fn_abi_of_instance, cannot adjust for foreign ABI: {e:?}",
)
}
}
}

View File

@ -913,6 +913,15 @@ pub struct LayoutOf {
pub ty_layout: String, pub ty_layout: String,
} }
#[derive(Diagnostic)]
#[diag(passes_abi_of)]
pub struct AbiOf {
#[primary_span]
pub span: Span,
pub fn_name: Symbol,
pub fn_abi: String,
}
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(passes_unrecognized_field)] #[diag(passes_unrecognized_field)]
pub struct UnrecognizedField { pub struct UnrecognizedField {

View File

@ -11,16 +11,17 @@ use rustc_target::abi::{HasDataLayout, TargetDataLayout};
use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField}; use crate::errors::{Abi, Align, HomogeneousAggregate, LayoutOf, Size, UnrecognizedField};
pub fn test_layout(tcx: TyCtxt<'_>) { pub fn test_layout(tcx: TyCtxt<'_>) {
if tcx.features().rustc_attrs { if !tcx.features().rustc_attrs {
// if the `rustc_attrs` feature is not enabled, don't bother testing layout // if the `rustc_attrs` feature is not enabled, don't bother testing layout
for id in tcx.hir().items() { return;
if matches!( }
tcx.def_kind(id.owner_id), for id in tcx.hir().items() {
DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union if matches!(
) { tcx.def_kind(id.owner_id),
for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) { DefKind::TyAlias { .. } | DefKind::Enum | DefKind::Struct | DefKind::Union
dump_layout_of(tcx, id.owner_id.def_id, attr); ) {
} for attr in tcx.get_attrs(id.owner_id, sym::rustc_layout) {
dump_layout_of(tcx, id.owner_id.def_id, attr);
} }
} }
} }

View File

@ -24,6 +24,7 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_fluent_macro::fluent_messages; use rustc_fluent_macro::fluent_messages;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
pub mod abi_test;
mod check_attr; mod check_attr;
mod check_const; mod check_const;
pub mod dead; pub mod dead;

View File

@ -41,7 +41,7 @@ use rustc_query_system::query::{
}; };
use rustc_query_system::HandleCycleError; use rustc_query_system::HandleCycleError;
use rustc_query_system::Value; use rustc_query_system::Value;
use rustc_span::Span; use rustc_span::{ErrorGuaranteed, Span};
#[macro_use] #[macro_use]
mod plumbing; mod plumbing;
@ -146,8 +146,9 @@ where
self, self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
cycle: &[QueryInfo<DepKind>], cycle: &[QueryInfo<DepKind>],
guar: ErrorGuaranteed,
) -> Self::Value { ) -> Self::Value {
(self.dynamic.value_from_cycle_error)(tcx, cycle) (self.dynamic.value_from_cycle_error)(tcx, cycle, guar)
} }
#[inline(always)] #[inline(always)]

View File

@ -605,8 +605,8 @@ macro_rules! define_queries {
} { } {
|_tcx, _key, _prev_index, _index| None |_tcx, _key, _prev_index, _index| None
}), }),
value_from_cycle_error: |tcx, cycle| { value_from_cycle_error: |tcx, cycle, guar| {
let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle); let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle, guar);
erase(result) erase(result)
}, },
loadable_from_disk: |_tcx, _key, _index| { loadable_from_disk: |_tcx, _key, _index| {

View File

@ -8,6 +8,7 @@ use crate::query::DepNodeIndex;
use crate::query::{QueryContext, QueryInfo, QueryState}; use crate::query::{QueryContext, QueryInfo, QueryState};
use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fingerprint::Fingerprint;
use rustc_span::ErrorGuaranteed;
use std::fmt::Debug; use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
@ -57,6 +58,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
self, self,
tcx: Qcx::DepContext, tcx: Qcx::DepContext,
cycle: &[QueryInfo<Qcx::DepKind>], cycle: &[QueryInfo<Qcx::DepKind>],
guar: ErrorGuaranteed,
) -> Self::Value; ) -> Self::Value;
fn anon(self) -> bool; fn anon(self) -> bool;

View File

@ -148,8 +148,8 @@ where
use HandleCycleError::*; use HandleCycleError::*;
match query.handle_cycle_error() { match query.handle_cycle_error() {
Error => { Error => {
error.emit(); let guar = error.emit();
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar)
} }
Fatal => { Fatal => {
error.emit(); error.emit();
@ -157,8 +157,8 @@ where
unreachable!() unreachable!()
} }
DelayBug => { DelayBug => {
error.delay_as_bug(); let guar = error.delay_as_bug();
query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle) query.value_from_cycle_error(*qcx.dep_context(), &cycle_error.cycle, guar)
} }
} }
} }
@ -300,7 +300,18 @@ where
match result { match result {
Ok(()) => { Ok(()) => {
let Some((v, index)) = query.query_cache(qcx).lookup(&key) else { let Some((v, index)) = query.query_cache(qcx).lookup(&key) else {
cold_path(|| panic!("value must be in cache after waiting")) cold_path(|| {
// We didn't find the query result in the query cache. Check if it was
// poisoned due to a panic instead.
let lock = query.query_state(qcx).active.get_shard_by_value(&key).lock();
match lock.get(&key) {
// The query we waited on panicked. Continue unwinding here.
Some(QueryResult::Poisoned) => FatalError.raise(),
_ => panic!(
"query result must in the cache or the query must be poisoned after a wait"
),
}
})
}; };
qcx.dep_context().profiler().query_cache_hit(index.into()); qcx.dep_context().profiler().query_cache_hit(index.into());

View File

@ -1,12 +1,14 @@
use rustc_span::ErrorGuaranteed;
use crate::dep_graph::{DepContext, DepKind}; use crate::dep_graph::{DepContext, DepKind};
use crate::query::QueryInfo; use crate::query::QueryInfo;
pub trait Value<Tcx: DepContext, D: DepKind>: Sized { pub trait Value<Tcx: DepContext, D: DepKind>: Sized {
fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>]) -> Self; fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>], guar: ErrorGuaranteed) -> Self;
} }
impl<Tcx: DepContext, T, D: DepKind> Value<Tcx, D> for T { impl<Tcx: DepContext, T, D: DepKind> Value<Tcx, D> for T {
default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>]) -> T { default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo<D>], _guar: ErrorGuaranteed) -> T {
tcx.sess().abort_if_errors(); tcx.sess().abort_if_errors();
// Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
// non-trivial to define it earlier. // non-trivial to define it earlier.

View File

@ -772,9 +772,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.r.record_partial_res(ty.id, PartialRes::new(res)); self.r.record_partial_res(ty.id, PartialRes::new(res));
visit::walk_ty(self, ty) visit::walk_ty(self, ty)
} }
TyKind::ImplTrait(..) => { TyKind::ImplTrait(node_id, _) => {
let candidates = self.lifetime_elision_candidates.take(); let candidates = self.lifetime_elision_candidates.take();
visit::walk_ty(self, ty); visit::walk_ty(self, ty);
self.record_lifetime_params_for_impl_trait(*node_id);
self.lifetime_elision_candidates = candidates; self.lifetime_elision_candidates = candidates;
} }
TyKind::TraitObject(bounds, ..) => { TyKind::TraitObject(bounds, ..) => {
@ -909,8 +910,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
&sig.decl.output, &sig.decl.output,
); );
if let Some((async_node_id, span)) = sig.header.asyncness.opt_return_id() { if let Some((async_node_id, _)) = sig.header.asyncness.opt_return_id() {
this.record_lifetime_params_for_impl_trait(async_node_id, span); this.record_lifetime_params_for_impl_trait(async_node_id);
} }
}, },
); );
@ -951,8 +952,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
&declaration.output, &declaration.output,
); );
if let Some((async_node_id, span)) = async_node_id { if let Some((async_node_id, _)) = async_node_id {
this.record_lifetime_params_for_impl_trait(async_node_id, span); this.record_lifetime_params_for_impl_trait(async_node_id);
} }
}, },
); );
@ -4367,7 +4368,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
/// We include all lifetime parameters, either named or "Fresh". /// We include all lifetime parameters, either named or "Fresh".
/// The order of those parameters does not matter, as long as it is /// The order of those parameters does not matter, as long as it is
/// deterministic. /// deterministic.
fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId, span: Span) { fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId) {
let mut extra_lifetime_params = vec![]; let mut extra_lifetime_params = vec![];
for rib in self.lifetime_ribs.iter().rev() { for rib in self.lifetime_ribs.iter().rev() {
@ -4380,14 +4381,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
extra_lifetime_params.extend(earlier_fresh); extra_lifetime_params.extend(earlier_fresh);
} }
} }
LifetimeRibKind::Generics { .. } => {} _ => {}
_ => {
// We are in a function definition. We should only find `Generics`
// and `AnonymousCreateParameter` inside the innermost `Item`.
span_bug!(span, "unexpected rib kind: {:?}", rib.kind)
}
} }
} }
self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params); self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params);
} }

View File

@ -1631,6 +1631,8 @@ options! {
"run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"), "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED], no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
"prevent automatic injection of the profiler_builtins crate"), "prevent automatic injection of the profiler_builtins crate"),
no_trait_vptr: bool = (false, parse_no_flag, [TRACKED],
"disable generation of trait vptr in vtable for upcasting"),
no_unique_section_names: bool = (false, parse_bool, [TRACKED], no_unique_section_names: bool = (false, parse_bool, [TRACKED],
"do not use unique names for text and data sections when -Z function-sections is used"), "do not use unique names for text and data sections when -Z function-sections is used"),
normalize_docs: bool = (false, parse_bool, [TRACKED], normalize_docs: bool = (false, parse_bool, [TRACKED],

View File

@ -21,6 +21,8 @@
#![feature(rustc_attrs)] #![feature(rustc_attrs)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(round_char_boundary)] #![feature(round_char_boundary)]
#![feature(read_buf)]
#![feature(new_uninit)]
#![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)] #![deny(rustc::diagnostic_outside_of_impl)]
#![allow(internal_features)] #![allow(internal_features)]

View File

@ -24,6 +24,8 @@ use std::sync::atomic::Ordering;
use std::fs; use std::fs;
use std::io; use std::io;
use std::io::BorrowedBuf;
use std::io::Read;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
@ -101,10 +103,13 @@ pub trait FileLoader {
fn file_exists(&self, path: &Path) -> bool; fn file_exists(&self, path: &Path) -> bool;
/// Read the contents of a UTF-8 file into memory. /// Read the contents of a UTF-8 file into memory.
/// This function must return a String because we normalize
/// source files, which may require resizing.
fn read_file(&self, path: &Path) -> io::Result<String>; fn read_file(&self, path: &Path) -> io::Result<String>;
/// Read the contents of a potentially non-UTF-8 file into memory. /// Read the contents of a potentially non-UTF-8 file into memory.
fn read_binary_file(&self, path: &Path) -> io::Result<Vec<u8>>; /// We don't normalize binary files, so we can start in an Lrc.
fn read_binary_file(&self, path: &Path) -> io::Result<Lrc<[u8]>>;
} }
/// A FileLoader that uses std::fs to load real files. /// A FileLoader that uses std::fs to load real files.
@ -119,8 +124,16 @@ impl FileLoader for RealFileLoader {
fs::read_to_string(path) fs::read_to_string(path)
} }
fn read_binary_file(&self, path: &Path) -> io::Result<Vec<u8>> { fn read_binary_file(&self, path: &Path) -> io::Result<Lrc<[u8]>> {
fs::read(path) let mut file = fs::File::open(path)?;
let len = file.metadata()?.len();
let mut bytes = Lrc::new_uninit_slice(len as usize);
let mut buf = BorrowedBuf::from(Lrc::get_mut(&mut bytes).unwrap());
file.read_buf_exact(buf.unfilled())?;
// SAFETY: If the read_buf_exact call returns Ok(()), then we have
// read len bytes and initialized the buffer.
Ok(unsafe { bytes.assume_init() })
} }
} }
@ -228,7 +241,7 @@ impl SourceMap {
/// ///
/// Unlike `load_file`, guarantees that no normalization like BOM-removal /// Unlike `load_file`, guarantees that no normalization like BOM-removal
/// takes place. /// takes place.
pub fn load_binary_file(&self, path: &Path) -> io::Result<Vec<u8>> { pub fn load_binary_file(&self, path: &Path) -> io::Result<Lrc<[u8]>> {
let bytes = self.file_loader.read_binary_file(path)?; let bytes = self.file_loader.read_binary_file(path)?;
// We need to add file to the `SourceMap`, so that it is present // We need to add file to the `SourceMap`, so that it is present

View File

@ -1281,6 +1281,7 @@ symbols! {
rust_eh_catch_typeinfo, rust_eh_catch_typeinfo,
rust_eh_personality, rust_eh_personality,
rustc, rustc,
rustc_abi,
rustc_allocator, rustc_allocator,
rustc_allocator_zeroed, rustc_allocator_zeroed,
rustc_allow_const_fn_unstable, rustc_allow_const_fn_unstable,
@ -1365,6 +1366,7 @@ symbols! {
rustc_trivial_field_reads, rustc_trivial_field_reads,
rustc_unsafe_specialization_marker, rustc_unsafe_specialization_marker,
rustc_variance, rustc_variance,
rustc_variance_of_opaques,
rustdoc, rustdoc,
rustdoc_internals, rustdoc_internals,
rustdoc_missing_doc_code_examples, rustdoc_missing_doc_code_examples,

View File

@ -579,10 +579,9 @@ pub enum Conv {
C, C,
Rust, Rust,
/// For things unlikely to be called, where smaller caller codegen is Cold,
/// preferred over raw speed. PreserveMost,
/// Stronger than just `#[cold]` because `fn` pointers might be incompatible. PreserveAll,
RustCold,
// Target-specific calling conventions. // Target-specific calling conventions.
ArmAapcs, ArmAapcs,
@ -605,9 +604,7 @@ pub enum Conv {
AvrInterrupt, AvrInterrupt,
AvrNonBlockingInterrupt, AvrNonBlockingInterrupt,
RiscvInterrupt { RiscvInterrupt { kind: RiscvInterruptKind },
kind: RiscvInterruptKind,
},
} }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]

View File

@ -96,7 +96,9 @@ impl ToJson for crate::abi::call::Conv {
let s = match self { let s = match self {
Self::C => "C", Self::C => "C",
Self::Rust => "Rust", Self::Rust => "Rust",
Self::RustCold => "RustCold", Self::Cold => "Cold",
Self::PreserveMost => "PreserveMost",
Self::PreserveAll => "PreserveAll",
Self::ArmAapcs => "ArmAapcs", Self::ArmAapcs => "ArmAapcs",
Self::CCmseNonSecureCall => "CCmseNonSecureCall", Self::CCmseNonSecureCall => "CCmseNonSecureCall",
Self::Msp430Intr => "Msp430Intr", Self::Msp430Intr => "Msp430Intr",

View File

@ -14,15 +14,33 @@ pub enum Abi {
// hashing tests. These are used in many places, so giving them stable values reduces test // hashing tests. These are used in many places, so giving them stable values reduces test
// churn. The specific values are meaningless. // churn. The specific values are meaningless.
Rust, Rust,
C { unwind: bool }, C {
Cdecl { unwind: bool }, unwind: bool,
Stdcall { unwind: bool }, },
Fastcall { unwind: bool }, Cdecl {
Vectorcall { unwind: bool }, unwind: bool,
Thiscall { unwind: bool }, },
Aapcs { unwind: bool }, Stdcall {
Win64 { unwind: bool }, unwind: bool,
SysV64 { unwind: bool }, },
Fastcall {
unwind: bool,
},
Vectorcall {
unwind: bool,
},
Thiscall {
unwind: bool,
},
Aapcs {
unwind: bool,
},
Win64 {
unwind: bool,
},
SysV64 {
unwind: bool,
},
PtxKernel, PtxKernel,
Msp430Interrupt, Msp430Interrupt,
X86Interrupt, X86Interrupt,
@ -32,11 +50,16 @@ pub enum Abi {
AvrNonBlockingInterrupt, AvrNonBlockingInterrupt,
CCmseNonSecureCall, CCmseNonSecureCall,
Wasm, Wasm,
System { unwind: bool }, System {
unwind: bool,
},
RustIntrinsic, RustIntrinsic,
RustCall, RustCall,
PlatformIntrinsic, PlatformIntrinsic,
Unadjusted, Unadjusted,
/// For things unlikely to be called, where reducing register pressure in
/// `extern "Rust"` callers is worth paying extra cost in the callee.
/// Stronger than just `#[cold]` because `fn` pointers might be incompatible.
RustCold, RustCold,
RiscvInterruptM, RiscvInterruptM,
RiscvInterruptS, RiscvInterruptS,

View File

@ -2216,7 +2216,7 @@ impl Default for TargetOptions {
mcount: "mcount".into(), mcount: "mcount".into(),
llvm_mcount_intrinsic: None, llvm_mcount_intrinsic: None,
llvm_abiname: "".into(), llvm_abiname: "".into(),
relax_elf_relocations: true, relax_elf_relocations: false,
llvm_args: cvs![], llvm_args: cvs![],
use_ctors_section: false, use_ctors_section: false,
eh_frame_header: true, eh_frame_header: true,
@ -2276,6 +2276,13 @@ impl Target {
Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi, Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind }, Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind },
// The Windows x64 calling convention we use for `extern "Rust"`
// <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation>
// expects the callee to save `xmm6` through `xmm15`, but `PreserveMost`
// (that we use by default for `extern "rust-cold"`) doesn't save any of those.
// So to avoid bloating callers, just use the Rust convention here.
Abi::RustCold if self.is_like_windows && self.arch == "x86_64" => Abi::Rust,
abi => abi, abi => abi,
} }
} }

View File

@ -69,6 +69,7 @@ pub fn target() -> Target {
position_independent_executables: true, position_independent_executables: true,
pre_link_args, pre_link_args,
override_export_symbols: Some(EXPORT_SYMBOLS.iter().cloned().map(Cow::from).collect()), override_export_symbols: Some(EXPORT_SYMBOLS.iter().cloned().map(Cow::from).collect()),
relax_elf_relocations: true,
..Default::default() ..Default::default()
}; };
Target { Target {

View File

@ -2743,12 +2743,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} }
ObligationCauseCode::BindingObligation(item_def_id, span) ObligationCauseCode::BindingObligation(item_def_id, span)
| ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..) => { | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..) => {
if self.tcx.is_diagnostic_item(sym::Send, item_def_id)
|| self.tcx.lang_items().sync_trait() == Some(item_def_id)
{
return;
}
let item_name = tcx.def_path_str(item_def_id); let item_name = tcx.def_path_str(item_def_id);
let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id)); let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id));
let mut multispan = MultiSpan::from(span); let mut multispan = MultiSpan::from(span);

View File

@ -548,7 +548,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.cause.span, obligation.cause.span,
"GATs in trait object shouldn't have been considered", "GATs in trait object shouldn't have been considered",
); );
return Err(SelectionError::Unimplemented); return Err(SelectionError::TraitNotObjectSafe(trait_predicate.trait_ref.def_id));
} }
// This maybe belongs in wf, but that can't (doesn't) handle // This maybe belongs in wf, but that can't (doesn't) handle

View File

@ -2346,14 +2346,15 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
} }
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
let ty = self.tcx().type_of(def_id);
if ty.skip_binder().references_error() {
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
}
// We can resolve the `impl Trait` to its concrete type, // We can resolve the `impl Trait` to its concrete type,
// which enforces a DAG between the functions requiring // which enforces a DAG between the functions requiring
// the auto trait bounds in question. // the auto trait bounds in question.
t.rebind(vec![ty.instantiate(self.tcx(), args)]) match self.tcx().type_of_opaque(def_id) {
Ok(ty) => t.rebind(vec![ty.instantiate(self.tcx(), args)]),
Err(_) => {
return Err(SelectionError::OpaqueTypeAutoTraitLeakageUnknown(def_id));
}
}
} }
}) })
} }

View File

@ -472,17 +472,11 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
let mut types_without_default_bounds = FxIndexSet::default(); let mut types_without_default_bounds = FxIndexSet::default();
let sized_trait = tcx.lang_items().sized_trait(); let sized_trait = tcx.lang_items().sized_trait();
if !args.is_empty() { let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
if !arg_names.is_empty() {
types_without_default_bounds.extend(args.types()); types_without_default_bounds.extend(args.types());
w.push('<'); w.push('<');
w.push_str( w.push_str(&arg_names.join(", "));
&args
.iter()
.map(|k| k.to_string())
.filter(|k| k != "'_")
.collect::<Vec<_>>()
.join(", "),
);
w.push('>'); w.push('>');
} }

View File

@ -152,7 +152,7 @@ fn prepare_vtable_segments_inner<'tcx, T>(
while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() { while let Some((inner_most_trait_ref, emit_vptr, mut siblings)) = stack.pop() {
segment_visitor(VtblSegment::TraitOwnEntries { segment_visitor(VtblSegment::TraitOwnEntries {
trait_ref: inner_most_trait_ref, trait_ref: inner_most_trait_ref,
emit_vptr, emit_vptr: emit_vptr && !tcx.sess.opts.unstable_opts.no_trait_vptr,
})?; })?;
// If we've emitted (fed to `segment_visitor`) a trait that has methods present in the vtable, // If we've emitted (fed to `segment_visitor`) a trait that has methods present in the vtable,

View File

@ -172,7 +172,10 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
use rustc_target::spec::abi::Abi::*; use rustc_target::spec::abi::Abi::*;
match tcx.sess.target.adjust_abi(abi) { match tcx.sess.target.adjust_abi(abi) {
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
RustCold => Conv::RustCold,
// This is intentionally not using `Conv::Cold`, as that has to preserve
// even SIMD registers, which is generally not a good trade-off.
RustCold => Conv::PreserveMost,
// It's the ABI's job to select this, not ours. // It's the ABI's job to select this, not ours.
System { .. } => bug!("system abi should be selected elsewhere"), System { .. } => bug!("system abi should be selected elsewhere"),

View File

@ -343,18 +343,31 @@ extern "Rust" {
fn __rust_alloc_error_handler(size: usize, align: usize) -> !; fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
} }
/// Abort on memory allocation error or failure. /// Signal a memory allocation error.
/// ///
/// Callers of memory allocation APIs wishing to abort computation /// Callers of memory allocation APIs wishing to cease execution
/// in response to an allocation error are encouraged to call this function, /// in response to an allocation error are encouraged to call this function,
/// rather than directly invoking `panic!` or similar. /// rather than directly invoking [`panic!`] or similar.
/// ///
/// The default behavior of this function is to print a message to standard error /// This function is guaranteed to diverge (not return normally with a value), but depending on
/// and abort the process. /// global configuration, it may either panic (resulting in unwinding or aborting as per
/// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`]. /// configuration for all panics), or abort the process (with no unwinding).
///
/// The default behavior is:
///
/// * If the binary links against `std` (typically the case), then
/// print a message to standard error and abort the process.
/// This behavior can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
/// Future versions of Rust may panic by default instead.
///
/// * If the binary does not link against `std` (all of its crates are marked
/// [`#![no_std]`][no_std]), then call [`panic!`] with a message.
/// [The panic handler] applies as to any panic.
/// ///
/// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
/// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
/// [The panic handler]: https://doc.rust-lang.org/reference/runtime.html#the-panic_handler-attribute
/// [no_std]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute
#[stable(feature = "global_alloc", since = "1.28.0")] #[stable(feature = "global_alloc", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")] #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
#[cfg(all(not(no_global_oom_handling), not(test)))] #[cfg(all(not(no_global_oom_handling), not(test)))]
@ -395,9 +408,10 @@ pub mod __alloc_error_handler {
if unsafe { __rust_alloc_error_handler_should_panic != 0 } { if unsafe { __rust_alloc_error_handler_should_panic != 0 } {
panic!("memory allocation of {size} bytes failed") panic!("memory allocation of {size} bytes failed")
} else { } else {
core::panicking::panic_nounwind_fmt(format_args!( core::panicking::panic_nounwind_fmt(
"memory allocation of {size} bytes failed" format_args!("memory allocation of {size} bytes failed"),
)) /* force_no_backtrace */ false,
)
} }
} }
} }

View File

@ -79,10 +79,12 @@ macro_rules! vec {
/// ///
/// The first argument `format!` receives is a format string. This must be a string /// The first argument `format!` receives is a format string. This must be a string
/// literal. The power of the formatting string is in the `{}`s contained. /// literal. The power of the formatting string is in the `{}`s contained.
///
/// Additional parameters passed to `format!` replace the `{}`s within the /// Additional parameters passed to `format!` replace the `{}`s within the
/// formatting string in the order given unless named or positional parameters /// formatting string in the order given unless named or positional parameters
/// are used; see [`std::fmt`] for more information. /// are used.
///
/// See [the formatting syntax documentation in `std::fmt`](../std/fmt/index.html)
/// for details.
/// ///
/// A common use for `format!` is concatenation and interpolation of strings. /// A common use for `format!` is concatenation and interpolation of strings.
/// The same convention is used with [`print!`] and [`write!`] macros, /// The same convention is used with [`print!`] and [`write!`] macros,
@ -91,7 +93,6 @@ macro_rules! vec {
/// To convert a single value to a string, use the [`to_string`] method. This /// To convert a single value to a string, use the [`to_string`] method. This
/// will use the [`Display`] formatting trait. /// will use the [`Display`] formatting trait.
/// ///
/// [`std::fmt`]: ../std/fmt/index.html
/// [`print!`]: ../std/macro.print.html /// [`print!`]: ../std/macro.print.html
/// [`write!`]: core::write /// [`write!`]: core::write
/// [`to_string`]: crate::string::ToString /// [`to_string`]: crate::string::ToString

View File

@ -849,7 +849,8 @@ pub(crate) mod builtin {
/// assert_eq!(display, debug); /// assert_eq!(display, debug);
/// ``` /// ```
/// ///
/// For more information, see the documentation in [`std::fmt`]. /// See [the formatting documentation in `std::fmt`](../std/fmt/index.html)
/// for details of the macro argument syntax, and further information.
/// ///
/// [`Display`]: crate::fmt::Display /// [`Display`]: crate::fmt::Display
/// [`Debug`]: crate::fmt::Debug /// [`Debug`]: crate::fmt::Debug

View File

@ -8,8 +8,8 @@ tests. `panic!` is closely tied with the `unwrap` method of both
[`Option`][ounwrap] and [`Result`][runwrap] enums. Both implementations call [`Option`][ounwrap] and [`Result`][runwrap] enums. Both implementations call
`panic!` when they are set to [`None`] or [`Err`] variants. `panic!` when they are set to [`None`] or [`Err`] variants.
When using `panic!()` you can specify a string payload, that is built using When using `panic!()` you can specify a string payload that is built using
the [`format!`] syntax. That payload is used when injecting the panic into [formatting syntax]. That payload is used when injecting the panic into
the calling Rust thread, causing the thread to panic entirely. the calling Rust thread, causing the thread to panic entirely.
The behavior of the default `std` hook, i.e. the code that runs directly The behavior of the default `std` hook, i.e. the code that runs directly
@ -18,6 +18,7 @@ after the panic is invoked, is to print the message payload to
call. You can override the panic hook using [`std::panic::set_hook()`]. call. You can override the panic hook using [`std::panic::set_hook()`].
Inside the hook a panic can be accessed as a `&dyn Any + Send`, Inside the hook a panic can be accessed as a `&dyn Any + Send`,
which contains either a `&str` or `String` for regular `panic!()` invocations. which contains either a `&str` or `String` for regular `panic!()` invocations.
(Whether a particular invocation contains the payload at type `&str` or `String` is unspecified and can change.)
To panic with a value of another other type, [`panic_any`] can be used. To panic with a value of another other type, [`panic_any`] can be used.
See also the macro [`compile_error!`], for raising errors during compilation. See also the macro [`compile_error!`], for raising errors during compilation.
@ -55,7 +56,7 @@ For more detailed information about error handling check out the [book] or the
[`panic_any`]: ../std/panic/fn.panic_any.html [`panic_any`]: ../std/panic/fn.panic_any.html
[`Box`]: ../std/boxed/struct.Box.html [`Box`]: ../std/boxed/struct.Box.html
[`Any`]: crate::any::Any [`Any`]: crate::any::Any
[`format!`]: ../std/macro.format.html [`format!` syntax]: ../std/fmt/index.html
[book]: ../book/ch09-00-error-handling.html [book]: ../book/ch09-00-error-handling.html
[`std::result`]: ../std/result/index.html [`std::result`]: ../std/result/index.html
@ -64,6 +65,29 @@ For more detailed information about error handling check out the [book] or the
If the main thread panics it will terminate all your threads and end your If the main thread panics it will terminate all your threads and end your
program with code `101`. program with code `101`.
# Editions
Behavior of the panic macros changed over editions.
## 2021 and later
In Rust 2021 and later, `panic!` always requires a format string and
the applicable format arguments, and is the same in `core` and `std`.
Use [`std::panic::panic_any(x)`](../std/panic/fn.panic_any.html) to
panic with an arbitrary payload.
## 2018 and 2015
In Rust Editions prior to 2021, `std::panic!(x)` with a single
argument directly uses that argument as a payload.
This is true even if the argument is a string literal.
For example, `panic!("problem: {reason}")` panics with a
payload of literally `"problem: {reason}"` (a `&'static str`).
`core::panic!(x)` with a single argument requires that `x` be `&str`,
but otherwise behaves like `std::panic!`. In particular, the string
need not be a literal, and is not interpreted as a format string.
# Examples # Examples
```should_panic ```should_panic

View File

@ -76,11 +76,8 @@ macro marker_impls {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "Send")] #[cfg_attr(not(test), rustc_diagnostic_item = "Send")]
#[rustc_on_unimplemented( #[rustc_on_unimplemented(
on(_Self = "std::rc::Rc<T, A>", note = "use `std::sync::Arc` instead of `std::rc::Rc`"),
message = "`{Self}` cannot be sent between threads safely", message = "`{Self}` cannot be sent between threads safely",
label = "`{Self}` cannot be sent between threads safely", label = "`{Self}` cannot be sent between threads safely"
note = "consider using `std::sync::Arc<{Self}>`; for more information visit \
<https://doc.rust-lang.org/book/ch16-03-shared-state.html>"
)] )]
pub unsafe auto trait Send { pub unsafe auto trait Send {
// empty. // empty.
@ -631,11 +628,8 @@ impl<T: ?Sized> Copy for &T {}
any(_Self = "core::cell::RefCell<T>", _Self = "std::cell::RefCell<T>"), any(_Self = "core::cell::RefCell<T>", _Self = "std::cell::RefCell<T>"),
note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead", note = "if you want to do aliasing and mutation between multiple threads, use `std::sync::RwLock` instead",
), ),
on(_Self = "std::rc::Rc<T, A>", note = "use `std::sync::Arc` instead of `std::rc::Rc`"),
message = "`{Self}` cannot be shared between threads safely", message = "`{Self}` cannot be shared between threads safely",
label = "`{Self}` cannot be shared between threads safely", label = "`{Self}` cannot be shared between threads safely"
note = "consider using `std::sync::Arc<{Self}>`; for more information visit \
<https://doc.rust-lang.org/book/ch16-03-shared-state.html>"
)] )]
pub unsafe auto trait Sync { pub unsafe auto trait Sync {
// FIXME(estebank): once support to add notes in `rustc_on_unimplemented` // FIXME(estebank): once support to add notes in `rustc_on_unimplemented`

View File

@ -1856,13 +1856,7 @@ impl fmt::Display for Ipv6Addr {
if f.precision().is_none() && f.width().is_none() { if f.precision().is_none() && f.width().is_none() {
let segments = self.segments(); let segments = self.segments();
// Special case for :: and ::1; otherwise they get written with the if let Some(ipv4) = self.to_ipv4_mapped() {
// IPv4 formatter
if self.is_unspecified() {
f.write_str("::")
} else if self.is_loopback() {
f.write_str("::1")
} else if let Some(ipv4) = self.to_ipv4_mapped() {
write!(f, "::ffff:{}", ipv4) write!(f, "::ffff:{}", ipv4)
} else { } else {
#[derive(Copy, Clone, Default)] #[derive(Copy, Clone, Default)]

View File

@ -277,6 +277,14 @@ pub mod consts {
#[stable(feature = "tau_constant", since = "1.47.0")] #[stable(feature = "tau_constant", since = "1.47.0")]
pub const TAU: f32 = 6.28318530717958647692528676655900577_f32; pub const TAU: f32 = 6.28318530717958647692528676655900577_f32;
/// The golden ratio (φ)
#[unstable(feature = "more_float_constants", issue = "103883")]
pub const PHI: f32 = 1.618033988749894848204586834365638118_f32;
/// The Euler-Mascheroni constant (γ)
#[unstable(feature = "more_float_constants", issue = "103883")]
pub const EGAMMA: f32 = 0.577215664901532860606512090082402431_f32;
/// π/2 /// π/2
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub const FRAC_PI_2: f32 = 1.57079632679489661923132169163975144_f32; pub const FRAC_PI_2: f32 = 1.57079632679489661923132169163975144_f32;
@ -301,6 +309,10 @@ pub mod consts {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub const FRAC_1_PI: f32 = 0.318309886183790671537767526745028724_f32; pub const FRAC_1_PI: f32 = 0.318309886183790671537767526745028724_f32;
/// 1/sqrt(π)
#[unstable(feature = "more_float_constants", issue = "103883")]
pub const FRAC_1_SQRT_PI: f32 = 0.564189583547756286948079451560772586_f32;
/// 2/π /// 2/π
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub const FRAC_2_PI: f32 = 0.636619772367581343075535053490057448_f32; pub const FRAC_2_PI: f32 = 0.636619772367581343075535053490057448_f32;
@ -317,6 +329,14 @@ pub mod consts {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub const FRAC_1_SQRT_2: f32 = 0.707106781186547524400844362104849039_f32; pub const FRAC_1_SQRT_2: f32 = 0.707106781186547524400844362104849039_f32;
/// sqrt(3)
#[unstable(feature = "more_float_constants", issue = "103883")]
pub const SQRT_3: f32 = 1.732050807568877293527446341505872367_f32;
/// 1/sqrt(3)
#[unstable(feature = "more_float_constants", issue = "103883")]
pub const FRAC_1_SQRT_3: f32 = 0.577350269189625764509148780501957456_f32;
/// Euler's number (e) /// Euler's number (e)
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub const E: f32 = 2.71828182845904523536028747135266250_f32; pub const E: f32 = 2.71828182845904523536028747135266250_f32;

View File

@ -277,6 +277,14 @@ pub mod consts {
#[stable(feature = "tau_constant", since = "1.47.0")] #[stable(feature = "tau_constant", since = "1.47.0")]
pub const TAU: f64 = 6.28318530717958647692528676655900577_f64; pub const TAU: f64 = 6.28318530717958647692528676655900577_f64;
/// The golden ratio (φ)
#[unstable(feature = "more_float_constants", issue = "103883")]
pub const PHI: f64 = 1.618033988749894848204586834365638118_f64;
/// The Euler-Mascheroni constant (γ)
#[unstable(feature = "more_float_constants", issue = "103883")]
pub const EGAMMA: f64 = 0.577215664901532860606512090082402431_f64;
/// π/2 /// π/2
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub const FRAC_PI_2: f64 = 1.57079632679489661923132169163975144_f64; pub const FRAC_PI_2: f64 = 1.57079632679489661923132169163975144_f64;
@ -301,6 +309,10 @@ pub mod consts {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub const FRAC_1_PI: f64 = 0.318309886183790671537767526745028724_f64; pub const FRAC_1_PI: f64 = 0.318309886183790671537767526745028724_f64;
/// 1/sqrt(π)
#[unstable(feature = "more_float_constants", issue = "103883")]
pub const FRAC_1_SQRT_PI: f64 = 0.564189583547756286948079451560772586_f64;
/// 2/π /// 2/π
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub const FRAC_2_PI: f64 = 0.636619772367581343075535053490057448_f64; pub const FRAC_2_PI: f64 = 0.636619772367581343075535053490057448_f64;
@ -317,6 +329,14 @@ pub mod consts {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub const FRAC_1_SQRT_2: f64 = 0.707106781186547524400844362104849039_f64; pub const FRAC_1_SQRT_2: f64 = 0.707106781186547524400844362104849039_f64;
/// sqrt(3)
#[unstable(feature = "more_float_constants", issue = "103883")]
pub const SQRT_3: f64 = 1.732050807568877293527446341505872367_f64;
/// 1/sqrt(3)
#[unstable(feature = "more_float_constants", issue = "103883")]
pub const FRAC_1_SQRT_3: f64 = 0.577350269189625764509148780501957456_f64;
/// Euler's number (e) /// Euler's number (e)
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub const E: f64 = 2.71828182845904523536028747135266250_f64; pub const E: f64 = 2.71828182845904523536028747135266250_f64;

View File

@ -217,8 +217,13 @@ pub trait Drop {
/// ///
/// # Panics /// # Panics
/// ///
/// Given that a [`panic!`] will call `drop` as it unwinds, any [`panic!`] /// Implementations should generally avoid [`panic!`]ing, because `drop()` may itself be called
/// in a `drop` implementation will likely abort. /// during unwinding due to a panic, and if the `drop()` panics in that situation (a “double
/// panic”), this will likely abort the program. It is possible to check [`panicking()`] first,
/// which may be desirable for a `Drop` implementation that is reporting a bug of the kind
/// “you didn't finish using this before it was dropped”; but most types should simply clean up
/// their owned allocations or other resources and return normally from `drop()`, regardless of
/// what state they are in.
/// ///
/// Note that even if this panics, the value is considered to be dropped; /// Note that even if this panics, the value is considered to be dropped;
/// you must not cause `drop` to be called again. This is normally automatically /// you must not cause `drop` to be called again. This is normally automatically
@ -227,6 +232,7 @@ pub trait Drop {
/// ///
/// [E0040]: ../../error_codes/E0040.html /// [E0040]: ../../error_codes/E0040.html
/// [`panic!`]: crate::panic! /// [`panic!`]: crate::panic!
/// [`panicking()`]: ../../std/thread/fn.panicking.html
/// [`mem::drop`]: drop /// [`mem::drop`]: drop
/// [`ptr::drop_in_place`]: crate::ptr::drop_in_place /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]

View File

@ -28,6 +28,7 @@ pub struct PanicInfo<'a> {
message: Option<&'a fmt::Arguments<'a>>, message: Option<&'a fmt::Arguments<'a>>,
location: &'a Location<'a>, location: &'a Location<'a>,
can_unwind: bool, can_unwind: bool,
force_no_backtrace: bool,
} }
impl<'a> PanicInfo<'a> { impl<'a> PanicInfo<'a> {
@ -42,9 +43,10 @@ impl<'a> PanicInfo<'a> {
message: Option<&'a fmt::Arguments<'a>>, message: Option<&'a fmt::Arguments<'a>>,
location: &'a Location<'a>, location: &'a Location<'a>,
can_unwind: bool, can_unwind: bool,
force_no_backtrace: bool,
) -> Self { ) -> Self {
struct NoPayload; struct NoPayload;
PanicInfo { location, message, payload: &NoPayload, can_unwind } PanicInfo { location, message, payload: &NoPayload, can_unwind, force_no_backtrace }
} }
#[unstable( #[unstable(
@ -141,6 +143,17 @@ impl<'a> PanicInfo<'a> {
pub fn can_unwind(&self) -> bool { pub fn can_unwind(&self) -> bool {
self.can_unwind self.can_unwind
} }
#[unstable(
feature = "panic_internals",
reason = "internal details of the implementation of the `panic!` and related macros",
issue = "none"
)]
#[doc(hidden)]
#[inline]
pub fn force_no_backtrace(&self) -> bool {
self.force_no_backtrace
}
} }
#[stable(feature = "panic_hook_display", since = "1.26.0")] #[stable(feature = "panic_hook_display", since = "1.26.0")]

View File

@ -61,7 +61,12 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
fn panic_impl(pi: &PanicInfo<'_>) -> !; fn panic_impl(pi: &PanicInfo<'_>) -> !;
} }
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true); let pi = PanicInfo::internal_constructor(
Some(&fmt),
Location::caller(),
/* can_unwind */ true,
/* force_no_backtrace */ false,
);
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
unsafe { panic_impl(&pi) } unsafe { panic_impl(&pi) }
@ -77,7 +82,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
// and unwinds anyway, we will hit the "unwinding out of nounwind function" guard, // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard,
// which causes a "panic in a function that cannot unwind". // which causes a "panic in a function that cannot unwind".
#[rustc_nounwind] #[rustc_nounwind]
pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>) -> ! { pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! {
if cfg!(feature = "panic_immediate_abort") { if cfg!(feature = "panic_immediate_abort") {
super::intrinsics::abort() super::intrinsics::abort()
} }
@ -90,7 +95,12 @@ pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>) -> ! {
} }
// PanicInfo with the `can_unwind` flag set to false forces an abort. // PanicInfo with the `can_unwind` flag set to false forces an abort.
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false); let pi = PanicInfo::internal_constructor(
Some(&fmt),
Location::caller(),
/* can_unwind */ false,
force_no_backtrace,
);
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
unsafe { panic_impl(&pi) } unsafe { panic_impl(&pi) }
@ -123,7 +133,15 @@ pub const fn panic(expr: &'static str) -> ! {
#[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics
#[rustc_nounwind] #[rustc_nounwind]
pub fn panic_nounwind(expr: &'static str) -> ! { pub fn panic_nounwind(expr: &'static str) -> ! {
panic_nounwind_fmt(fmt::Arguments::new_const(&[expr])); panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ false);
}
/// Like `panic_nounwind`, but also inhibits showing a backtrace.
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[rustc_nounwind]
pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ true);
} }
#[inline] #[inline]
@ -172,9 +190,12 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
super::intrinsics::abort() super::intrinsics::abort()
} }
panic_nounwind_fmt(format_args!( panic_nounwind_fmt(
"misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}" format_args!(
)) "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
),
/* force_no_backtrace */ false,
)
} }
/// Panic because we cannot unwind out of a function. /// Panic because we cannot unwind out of a function.
@ -205,7 +226,7 @@ fn panic_cannot_unwind() -> ! {
#[rustc_nounwind] #[rustc_nounwind]
fn panic_in_cleanup() -> ! { fn panic_in_cleanup() -> ! {
// Keep the text in sync with `UnwindTerminateReason::as_str` in `rustc_middle`. // Keep the text in sync with `UnwindTerminateReason::as_str` in `rustc_middle`.
panic_nounwind("panic in a destructor during cleanup") panic_nounwind_nobacktrace("panic in a destructor during cleanup")
} }
/// This function is used instead of panic_fmt in const eval. /// This function is used instead of panic_fmt in const eval.

View File

@ -656,10 +656,10 @@ impl Duration {
#[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")] #[rustc_const_stable(feature = "duration_consts_2", since = "1.58.0")]
pub const fn checked_div(self, rhs: u32) -> Option<Duration> { pub const fn checked_div(self, rhs: u32) -> Option<Duration> {
if rhs != 0 { if rhs != 0 {
let secs = self.secs / (rhs as u64); let (secs, extra_secs) = (self.secs / (rhs as u64), self.secs % (rhs as u64));
let carry = self.secs - secs * (rhs as u64); let (mut nanos, extra_nanos) = (self.nanos.0 / rhs, self.nanos.0 % rhs);
let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); nanos +=
let nanos = self.nanos.0 / rhs + (extra_nanos as u32); ((extra_secs * (NANOS_PER_SEC as u64) + extra_nanos as u64) / (rhs as u64)) as u32;
debug_assert!(nanos < NANOS_PER_SEC); debug_assert!(nanos < NANOS_PER_SEC);
Some(Duration::new(secs, nanos)) Some(Duration::new(secs, nanos))
} else { } else {

View File

@ -170,6 +170,7 @@ fn saturating_mul() {
fn div() { fn div() {
assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333)); assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
assert_eq!(Duration::new(1, 1) / 7, Duration::new(0, 142_857_143));
assert_eq!(Duration::new(99, 999_999_000) / 100, Duration::new(0, 999_999_990)); assert_eq!(Duration::new(99, 999_999_000) / 100, Duration::new(0, 999_999_990));
} }

View File

@ -290,15 +290,29 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
/// Registers a custom allocation error hook, replacing any that was previously registered. /// Registers a custom allocation error hook, replacing any that was previously registered.
/// ///
/// The allocation error hook is invoked when an infallible memory allocation fails, before /// The allocation error hook is invoked when an infallible memory allocation fails — that is,
/// the runtime aborts. The default hook prints a message to standard error, /// as a consequence of calling [`handle_alloc_error`] — before the runtime aborts.
/// but this behavior can be customized with the [`set_alloc_error_hook`] and
/// [`take_alloc_error_hook`] functions.
/// ///
/// The hook is provided with a `Layout` struct which contains information /// The allocation error hook is a global resource. [`take_alloc_error_hook`] may be used to
/// retrieve a previously registered hook and wrap or discard it.
///
/// # What the provided `hook` function should expect
///
/// The hook function is provided with a [`Layout`] struct which contains information
/// about the allocation that failed. /// about the allocation that failed.
/// ///
/// The allocation error hook is a global resource. /// The hook function may choose to panic or abort; in the event that it returns normally, this
/// will cause an immediate abort.
///
/// Since [`take_alloc_error_hook`] is a safe function that allows retrieving the hook, the hook
/// function must be _sound_ to call even if no memory allocations were attempted.
///
/// # The default hook
///
/// The default hook, used if [`set_alloc_error_hook`] is never called, prints a message to
/// standard error (and then returns, causing the runtime to abort the process).
/// Compiler options may cause it to panic instead, and the default behavior may be changed
/// to panicking in future versions of Rust.
/// ///
/// # Examples /// # Examples
/// ///

View File

@ -41,6 +41,9 @@ macro_rules! panic {
/// Use `print!` only for the primary output of your program. Use /// Use `print!` only for the primary output of your program. Use
/// [`eprint!`] instead to print error and progress messages. /// [`eprint!`] instead to print error and progress messages.
/// ///
/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html)
/// for details of the macro argument syntax.
///
/// [flush]: crate::io::Write::flush /// [flush]: crate::io::Write::flush
/// [`println!`]: crate::println /// [`println!`]: crate::println
/// [`eprint!`]: crate::eprint /// [`eprint!`]: crate::eprint
@ -103,6 +106,9 @@ macro_rules! print {
/// Use `println!` only for the primary output of your program. Use /// Use `println!` only for the primary output of your program. Use
/// [`eprintln!`] instead to print error and progress messages. /// [`eprintln!`] instead to print error and progress messages.
/// ///
/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html)
/// for details of the macro argument syntax.
///
/// [`std::fmt`]: crate::fmt /// [`std::fmt`]: crate::fmt
/// [`eprintln!`]: crate::eprintln /// [`eprintln!`]: crate::eprintln
/// [lock]: crate::io::Stdout /// [lock]: crate::io::Stdout
@ -150,6 +156,9 @@ macro_rules! println {
/// [`io::stderr`]: crate::io::stderr /// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout /// [`io::stdout`]: crate::io::stdout
/// ///
/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html)
/// for details of the macro argument syntax.
///
/// # Panics /// # Panics
/// ///
/// Panics if writing to `io::stderr` fails. /// Panics if writing to `io::stderr` fails.
@ -181,6 +190,9 @@ macro_rules! eprint {
/// Use `eprintln!` only for error and progress messages. Use `println!` /// Use `eprintln!` only for error and progress messages. Use `println!`
/// instead for the primary output of your program. /// instead for the primary output of your program.
/// ///
/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html)
/// for details of the macro argument syntax.
///
/// [`io::stderr`]: crate::io::stderr /// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout /// [`io::stdout`]: crate::io::stdout
/// [`println!`]: crate::println /// [`println!`]: crate::println

View File

@ -662,7 +662,7 @@ fn test_send_vectored_fds_unix_stream() {
} }
} }
#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))] #[cfg(any(target_os = "android", target_os = "linux"))]
#[test] #[test]
#[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets
fn test_send_vectored_with_ancillary_to_unix_datagram() { fn test_send_vectored_with_ancillary_to_unix_datagram() {

View File

@ -192,6 +192,66 @@ pub trait CommandExt: Sealed {
/// ``` /// ```
#[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")] #[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
fn async_pipes(&mut self, always_async: bool) -> &mut process::Command; fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
/// Sets a raw attribute on the command, providing extended configuration options for Windows processes.
///
/// This method allows you to specify custom attributes for a child process on Windows systems using raw attribute values.
/// Raw attributes provide extended configurability for process creation, but their usage can be complex and potentially unsafe.
///
/// The `attribute` parameter specifies the raw attribute to be set, while the `value` parameter holds the value associated with that attribute.
/// Please refer to the [`windows-rs`](https://microsoft.github.io/windows-docs-rs/doc/windows/) documentation or the [`Win32 API documentation`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute) for detailed information about available attributes and their meanings.
///
/// # Note
///
/// The maximum number of raw attributes is the value of [`u32::MAX`].
/// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error` indicating that the maximum number of attributes has been exceeded.
/// # Safety
///
/// The usage of raw attributes is potentially unsafe and should be done with caution. Incorrect attribute values or improper configuration can lead to unexpected behavior or errors.
///
/// # Example
///
/// The following example demonstrates how to create a child process with a specific parent process ID using a raw attribute.
///
/// ```rust
/// #![feature(windows_process_extensions_raw_attribute)]
/// use std::os::windows::{process::CommandExt, io::AsRawHandle};
/// use std::process::Command;
///
/// # struct ProcessDropGuard(std::process::Child);
/// # impl Drop for ProcessDropGuard {
/// # fn drop(&mut self) {
/// # let _ = self.0.kill();
/// # }
/// # }
///
/// let parent = Command::new("cmd").spawn()?;
///
/// let mut child_cmd = Command::new("cmd");
///
/// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
///
/// unsafe {
/// child_cmd.raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.as_raw_handle() as isize);
/// }
/// #
/// # let parent = ProcessDropGuard(parent);
///
/// let mut child = child_cmd.spawn()?;
///
/// # child.kill()?;
/// # Ok::<(), std::io::Error>(())
/// ```
///
/// # Safety Note
///
/// Remember that improper use of raw attributes can lead to undefined behavior or security vulnerabilities. Always consult the documentation and ensure proper attribute values are used.
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
&mut self,
attribute: usize,
value: T,
) -> &mut process::Command;
} }
#[stable(feature = "windows_process_extensions", since = "1.16.0")] #[stable(feature = "windows_process_extensions", since = "1.16.0")]
@ -219,6 +279,15 @@ impl CommandExt for process::Command {
let _ = always_async; let _ = always_async;
self self
} }
unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
&mut self,
attribute: usize,
value: T,
) -> &mut process::Command {
self.as_inner_mut().raw_attribute(attribute, value);
self
}
} }
#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")] #[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]

View File

@ -246,7 +246,9 @@ fn default_hook(info: &PanicInfo<'_>) {
pub fn panic_hook_with_disk_dump(info: &PanicInfo<'_>, path: Option<&crate::path::Path>) { pub fn panic_hook_with_disk_dump(info: &PanicInfo<'_>, path: Option<&crate::path::Path>) {
// If this is a double panic, make sure that we print a backtrace // If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled. // for this panic. Otherwise only print it if logging is enabled.
let backtrace = if panic_count::get_count() >= 2 { let backtrace = if info.force_no_backtrace() {
None
} else if panic_count::get_count() >= 2 {
BacktraceStyle::full() BacktraceStyle::full()
} else { } else {
crate::panic::get_backtrace_style() crate::panic::get_backtrace_style()
@ -294,7 +296,7 @@ pub fn panic_hook_with_disk_dump(info: &PanicInfo<'_>, path: Option<&crate::path
} }
} }
} }
// If backtraces aren't supported, do nothing. // If backtraces aren't supported or are forced-off, do nothing.
None => {} None => {}
} }
}; };
@ -615,14 +617,23 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
let loc = info.location().unwrap(); // The current implementation always returns Some let loc = info.location().unwrap(); // The current implementation always returns Some
let msg = info.message().unwrap(); // The current implementation always returns Some let msg = info.message().unwrap(); // The current implementation always returns Some
crate::sys_common::backtrace::__rust_end_short_backtrace(move || { crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
// FIXME: can we just pass `info` along rather than taking it apart here, only to have
// `rust_panic_with_hook` construct a new `PanicInfo`?
if let Some(msg) = msg.as_str() { if let Some(msg) = msg.as_str() {
rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind()); rust_panic_with_hook(
&mut StrPanicPayload(msg),
info.message(),
loc,
info.can_unwind(),
info.force_no_backtrace(),
);
} else { } else {
rust_panic_with_hook( rust_panic_with_hook(
&mut PanicPayload::new(msg), &mut PanicPayload::new(msg),
info.message(), info.message(),
loc, loc,
info.can_unwind(), info.can_unwind(),
info.force_no_backtrace(),
); );
} }
}) })
@ -647,7 +658,13 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
let loc = Location::caller(); let loc = Location::caller();
return crate::sys_common::backtrace::__rust_end_short_backtrace(move || { return crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc, true) rust_panic_with_hook(
&mut PanicPayload::new(msg),
None,
loc,
/* can_unwind */ true,
/* force_no_backtrace */ false,
)
}); });
struct PanicPayload<A> { struct PanicPayload<A> {
@ -693,6 +710,7 @@ fn rust_panic_with_hook(
message: Option<&fmt::Arguments<'_>>, message: Option<&fmt::Arguments<'_>>,
location: &Location<'_>, location: &Location<'_>,
can_unwind: bool, can_unwind: bool,
force_no_backtrace: bool,
) -> ! { ) -> ! {
let must_abort = panic_count::increase(true); let must_abort = panic_count::increase(true);
@ -707,14 +725,20 @@ fn rust_panic_with_hook(
panic_count::MustAbort::AlwaysAbort => { panic_count::MustAbort::AlwaysAbort => {
// Unfortunately, this does not print a backtrace, because creating // Unfortunately, this does not print a backtrace, because creating
// a `Backtrace` will allocate, which we must to avoid here. // a `Backtrace` will allocate, which we must to avoid here.
let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind); let panicinfo = PanicInfo::internal_constructor(
message,
location,
can_unwind,
force_no_backtrace,
);
rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n"); rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n");
} }
} }
crate::sys::abort_internal(); crate::sys::abort_internal();
} }
let mut info = PanicInfo::internal_constructor(message, location, can_unwind); let mut info =
PanicInfo::internal_constructor(message, location, can_unwind, force_no_backtrace);
let hook = HOOK.read().unwrap_or_else(PoisonError::into_inner); let hook = HOOK.read().unwrap_or_else(PoisonError::into_inner);
match *hook { match *hook {
// Some platforms (like wasm) know that printing to stderr won't ever actually // Some platforms (like wasm) know that printing to stderr won't ever actually

View File

@ -434,6 +434,91 @@ fn test_creation_flags() {
assert!(events > 0); assert!(events > 0);
} }
/// Tests proc thread attributes by spawning a process with a custom parent process,
/// then comparing the parent process ID with the expected parent process ID.
#[test]
#[cfg(windows)]
fn test_proc_thread_attributes() {
use crate::mem;
use crate::os::windows::io::AsRawHandle;
use crate::os::windows::process::CommandExt;
use crate::sys::c::{CloseHandle, BOOL, HANDLE};
use crate::sys::cvt;
#[repr(C)]
#[allow(non_snake_case)]
struct PROCESSENTRY32W {
dwSize: u32,
cntUsage: u32,
th32ProcessID: u32,
th32DefaultHeapID: usize,
th32ModuleID: u32,
cntThreads: u32,
th32ParentProcessID: u32,
pcPriClassBase: i32,
dwFlags: u32,
szExeFile: [u16; 260],
}
extern "system" {
fn CreateToolhelp32Snapshot(dwflags: u32, th32processid: u32) -> HANDLE;
fn Process32First(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL;
fn Process32Next(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL;
}
const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
const TH32CS_SNAPPROCESS: u32 = 0x00000002;
struct ProcessDropGuard(crate::process::Child);
impl Drop for ProcessDropGuard {
fn drop(&mut self) {
let _ = self.0.kill();
}
}
let parent = ProcessDropGuard(Command::new("cmd").spawn().unwrap());
let mut child_cmd = Command::new("cmd");
unsafe {
child_cmd
.raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.0.as_raw_handle() as isize);
}
let child = ProcessDropGuard(child_cmd.spawn().unwrap());
let h_snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
let mut process_entry = PROCESSENTRY32W {
dwSize: mem::size_of::<PROCESSENTRY32W>() as u32,
cntUsage: 0,
th32ProcessID: 0,
th32DefaultHeapID: 0,
th32ModuleID: 0,
cntThreads: 0,
th32ParentProcessID: 0,
pcPriClassBase: 0,
dwFlags: 0,
szExeFile: [0; 260],
};
unsafe { cvt(Process32First(h_snapshot, &mut process_entry as *mut _)) }.unwrap();
loop {
if child.0.id() == process_entry.th32ProcessID {
break;
}
unsafe { cvt(Process32Next(h_snapshot, &mut process_entry as *mut _)) }.unwrap();
}
unsafe { cvt(CloseHandle(h_snapshot)) }.unwrap();
assert_eq!(parent.0.id(), process_entry.th32ParentProcessID);
drop(child)
}
#[test] #[test]
fn test_command_implements_send_sync() { fn test_command_implements_send_sync() {
fn take_send_sync_type<T: Send + Sync>(_: T) {} fn take_send_sync_type<T: Send + Sync>(_: T) {}

View File

@ -101,7 +101,6 @@ pub extern "C" fn __rust_abort() {
// SAFETY: must be called only once during runtime initialization. // SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally. // NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) { pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
let _ = net::init();
args::init(argc, argv); args::init(argc, argv);
} }

View File

@ -33,13 +33,7 @@ pub fn cvt_gai(err: i32) -> io::Result<()> {
)) ))
} }
/// Checks whether the HermitCore's socket interface has been started already, and pub fn init() {}
/// if not, starts it.
pub fn init() {
if unsafe { netc::network_init() } < 0 {
panic!("Unable to initialize network interface");
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct Socket(FileDesc); pub struct Socket(FileDesc);

View File

@ -86,7 +86,11 @@ cfg_if::cfg_if! {
} else if #[cfg(target_os = "wasi")] { } else if #[cfg(target_os = "wasi")] {
#[inline] #[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
libc::aligned_alloc(layout.align(), layout.size()) as *mut u8 // C11 aligned_alloc requires that the size be a multiple of the alignment.
// Layout already checks that the size rounded up doesn't overflow isize::MAX.
let align = layout.align();
let size = layout.size().next_multiple_of(align);
libc::aligned_alloc(align, size) as *mut u8
} }
} else { } else {
#[inline] #[inline]

View File

@ -2510,6 +2510,7 @@ Windows.Win32.System.Threading.CreateProcessW
Windows.Win32.System.Threading.CreateThread Windows.Win32.System.Threading.CreateThread
Windows.Win32.System.Threading.DEBUG_ONLY_THIS_PROCESS Windows.Win32.System.Threading.DEBUG_ONLY_THIS_PROCESS
Windows.Win32.System.Threading.DEBUG_PROCESS Windows.Win32.System.Threading.DEBUG_PROCESS
Windows.Win32.System.Threading.DeleteProcThreadAttributeList
Windows.Win32.System.Threading.DETACHED_PROCESS Windows.Win32.System.Threading.DETACHED_PROCESS
Windows.Win32.System.Threading.ExitProcess Windows.Win32.System.Threading.ExitProcess
Windows.Win32.System.Threading.EXTENDED_STARTUPINFO_PRESENT Windows.Win32.System.Threading.EXTENDED_STARTUPINFO_PRESENT
@ -2524,8 +2525,10 @@ Windows.Win32.System.Threading.INFINITE
Windows.Win32.System.Threading.INHERIT_CALLER_PRIORITY Windows.Win32.System.Threading.INHERIT_CALLER_PRIORITY
Windows.Win32.System.Threading.INHERIT_PARENT_AFFINITY Windows.Win32.System.Threading.INHERIT_PARENT_AFFINITY
Windows.Win32.System.Threading.INIT_ONCE_INIT_FAILED Windows.Win32.System.Threading.INIT_ONCE_INIT_FAILED
Windows.Win32.System.Threading.InitializeProcThreadAttributeList
Windows.Win32.System.Threading.InitOnceBeginInitialize Windows.Win32.System.Threading.InitOnceBeginInitialize
Windows.Win32.System.Threading.InitOnceComplete Windows.Win32.System.Threading.InitOnceComplete
Windows.Win32.System.Threading.LPPROC_THREAD_ATTRIBUTE_LIST
Windows.Win32.System.Threading.LPTHREAD_START_ROUTINE Windows.Win32.System.Threading.LPTHREAD_START_ROUTINE
Windows.Win32.System.Threading.NORMAL_PRIORITY_CLASS Windows.Win32.System.Threading.NORMAL_PRIORITY_CLASS
Windows.Win32.System.Threading.OpenProcessToken Windows.Win32.System.Threading.OpenProcessToken
@ -2561,6 +2564,7 @@ Windows.Win32.System.Threading.STARTF_USEPOSITION
Windows.Win32.System.Threading.STARTF_USESHOWWINDOW Windows.Win32.System.Threading.STARTF_USESHOWWINDOW
Windows.Win32.System.Threading.STARTF_USESIZE Windows.Win32.System.Threading.STARTF_USESIZE
Windows.Win32.System.Threading.STARTF_USESTDHANDLES Windows.Win32.System.Threading.STARTF_USESTDHANDLES
Windows.Win32.System.Threading.STARTUPINFOEXW
Windows.Win32.System.Threading.STARTUPINFOW Windows.Win32.System.Threading.STARTUPINFOW
Windows.Win32.System.Threading.STARTUPINFOW_FLAGS Windows.Win32.System.Threading.STARTUPINFOW_FLAGS
Windows.Win32.System.Threading.SwitchToThread Windows.Win32.System.Threading.SwitchToThread
@ -2575,6 +2579,7 @@ Windows.Win32.System.Threading.TlsGetValue
Windows.Win32.System.Threading.TlsSetValue Windows.Win32.System.Threading.TlsSetValue
Windows.Win32.System.Threading.TryAcquireSRWLockExclusive Windows.Win32.System.Threading.TryAcquireSRWLockExclusive
Windows.Win32.System.Threading.TryAcquireSRWLockShared Windows.Win32.System.Threading.TryAcquireSRWLockShared
Windows.Win32.System.Threading.UpdateProcThreadAttribute
Windows.Win32.System.Threading.WaitForMultipleObjects Windows.Win32.System.Threading.WaitForMultipleObjects
Windows.Win32.System.Threading.WaitForSingleObject Windows.Win32.System.Threading.WaitForSingleObject
Windows.Win32.System.Threading.WakeAllConditionVariable Windows.Win32.System.Threading.WakeAllConditionVariable

View File

@ -155,6 +155,10 @@ extern "system" {
pub fn DeleteFileW(lpfilename: PCWSTR) -> BOOL; pub fn DeleteFileW(lpfilename: PCWSTR) -> BOOL;
} }
#[link(name = "kernel32")] #[link(name = "kernel32")]
extern "system" {
pub fn DeleteProcThreadAttributeList(lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST) -> ();
}
#[link(name = "kernel32")]
extern "system" { extern "system" {
pub fn DeviceIoControl( pub fn DeviceIoControl(
hdevice: HANDLE, hdevice: HANDLE,
@ -371,6 +375,15 @@ extern "system" {
) -> BOOL; ) -> BOOL;
} }
#[link(name = "kernel32")] #[link(name = "kernel32")]
extern "system" {
pub fn InitializeProcThreadAttributeList(
lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST,
dwattributecount: u32,
dwflags: u32,
lpsize: *mut usize,
) -> BOOL;
}
#[link(name = "kernel32")]
extern "system" { extern "system" {
pub fn MoveFileExW( pub fn MoveFileExW(
lpexistingfilename: PCWSTR, lpexistingfilename: PCWSTR,
@ -543,6 +556,18 @@ extern "system" {
pub fn TryAcquireSRWLockShared(srwlock: *mut RTL_SRWLOCK) -> BOOLEAN; pub fn TryAcquireSRWLockShared(srwlock: *mut RTL_SRWLOCK) -> BOOLEAN;
} }
#[link(name = "kernel32")] #[link(name = "kernel32")]
extern "system" {
pub fn UpdateProcThreadAttribute(
lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST,
dwflags: u32,
attribute: usize,
lpvalue: *const ::core::ffi::c_void,
cbsize: usize,
lppreviousvalue: *mut ::core::ffi::c_void,
lpreturnsize: *const usize,
) -> BOOL;
}
#[link(name = "kernel32")]
extern "system" { extern "system" {
pub fn WaitForMultipleObjects( pub fn WaitForMultipleObjects(
ncount: u32, ncount: u32,
@ -3567,6 +3592,7 @@ pub type LPOVERLAPPED_COMPLETION_ROUTINE = ::core::option::Option<
lpoverlapped: *mut OVERLAPPED, lpoverlapped: *mut OVERLAPPED,
) -> (), ) -> (),
>; >;
pub type LPPROC_THREAD_ATTRIBUTE_LIST = *mut ::core::ffi::c_void;
pub type LPPROGRESS_ROUTINE = ::core::option::Option< pub type LPPROGRESS_ROUTINE = ::core::option::Option<
unsafe extern "system" fn( unsafe extern "system" fn(
totalfilesize: i64, totalfilesize: i64,
@ -3833,6 +3859,17 @@ pub const STARTF_USESHOWWINDOW: STARTUPINFOW_FLAGS = 1u32;
pub const STARTF_USESIZE: STARTUPINFOW_FLAGS = 2u32; pub const STARTF_USESIZE: STARTUPINFOW_FLAGS = 2u32;
pub const STARTF_USESTDHANDLES: STARTUPINFOW_FLAGS = 256u32; pub const STARTF_USESTDHANDLES: STARTUPINFOW_FLAGS = 256u32;
#[repr(C)] #[repr(C)]
pub struct STARTUPINFOEXW {
pub StartupInfo: STARTUPINFOW,
pub lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST,
}
impl ::core::marker::Copy for STARTUPINFOEXW {}
impl ::core::clone::Clone for STARTUPINFOEXW {
fn clone(&self) -> Self {
*self
}
}
#[repr(C)]
pub struct STARTUPINFOW { pub struct STARTUPINFOW {
pub cb: u32, pub cb: u32,
pub lpReserved: PWSTR, pub lpReserved: PWSTR,

View File

@ -11,6 +11,7 @@ use crate::ffi::{OsStr, OsString};
use crate::fmt; use crate::fmt;
use crate::io::{self, Error, ErrorKind}; use crate::io::{self, Error, ErrorKind};
use crate::mem; use crate::mem;
use crate::mem::MaybeUninit;
use crate::num::NonZeroI32; use crate::num::NonZeroI32;
use crate::os::windows::ffi::{OsStrExt, OsStringExt}; use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle}; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
@ -166,6 +167,7 @@ pub struct Command {
stdout: Option<Stdio>, stdout: Option<Stdio>,
stderr: Option<Stdio>, stderr: Option<Stdio>,
force_quotes_enabled: bool, force_quotes_enabled: bool,
proc_thread_attributes: BTreeMap<usize, ProcThreadAttributeValue>,
} }
pub enum Stdio { pub enum Stdio {
@ -195,6 +197,7 @@ impl Command {
stdout: None, stdout: None,
stderr: None, stderr: None,
force_quotes_enabled: false, force_quotes_enabled: false,
proc_thread_attributes: Default::default(),
} }
} }
@ -245,6 +248,17 @@ impl Command {
self.cwd.as_ref().map(|cwd| Path::new(cwd)) self.cwd.as_ref().map(|cwd| Path::new(cwd))
} }
pub unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
&mut self,
attribute: usize,
value: T,
) {
self.proc_thread_attributes.insert(
attribute,
ProcThreadAttributeValue { size: mem::size_of::<T>(), data: Box::new(value) },
);
}
pub fn spawn( pub fn spawn(
&mut self, &mut self,
default: Stdio, default: Stdio,
@ -308,7 +322,6 @@ impl Command {
let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?; let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?;
let mut si = zeroed_startupinfo(); let mut si = zeroed_startupinfo();
si.cb = mem::size_of::<c::STARTUPINFOW>() as c::DWORD;
// If at least one of stdin, stdout or stderr are set (i.e. are non null) // If at least one of stdin, stdout or stderr are set (i.e. are non null)
// then set the `hStd` fields in `STARTUPINFO`. // then set the `hStd` fields in `STARTUPINFO`.
@ -322,6 +335,27 @@ impl Command {
si.hStdError = stderr.as_raw_handle(); si.hStdError = stderr.as_raw_handle();
} }
let si_ptr: *mut c::STARTUPINFOW;
let mut proc_thread_attribute_list;
let mut si_ex;
if !self.proc_thread_attributes.is_empty() {
si.cb = mem::size_of::<c::STARTUPINFOEXW>() as u32;
flags |= c::EXTENDED_STARTUPINFO_PRESENT;
proc_thread_attribute_list =
make_proc_thread_attribute_list(&self.proc_thread_attributes)?;
si_ex = c::STARTUPINFOEXW {
StartupInfo: si,
lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _,
};
si_ptr = &mut si_ex as *mut _ as _;
} else {
si.cb = mem::size_of::<c::STARTUPINFOW> as c::DWORD;
si_ptr = &mut si as *mut _ as _;
}
unsafe { unsafe {
cvt(c::CreateProcessW( cvt(c::CreateProcessW(
program.as_ptr(), program.as_ptr(),
@ -332,7 +366,7 @@ impl Command {
flags, flags,
envp, envp,
dirp, dirp,
&si, si_ptr,
&mut pi, &mut pi,
)) ))
}?; }?;
@ -831,6 +865,80 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
} }
} }
struct ProcThreadAttributeList(Box<[MaybeUninit<u8>]>);
impl Drop for ProcThreadAttributeList {
fn drop(&mut self) {
let lp_attribute_list = self.0.as_mut_ptr() as _;
unsafe { c::DeleteProcThreadAttributeList(lp_attribute_list) }
}
}
/// Wrapper around the value data to be used as a Process Thread Attribute.
struct ProcThreadAttributeValue {
data: Box<dyn Send + Sync>,
size: usize,
}
fn make_proc_thread_attribute_list(
attributes: &BTreeMap<usize, ProcThreadAttributeValue>,
) -> io::Result<ProcThreadAttributeList> {
// To initialize our ProcThreadAttributeList, we need to determine
// how many bytes to allocate for it. The Windows API simplifies this process
// by allowing us to call `InitializeProcThreadAttributeList` with
// a null pointer to retrieve the required size.
let mut required_size = 0;
let Ok(attribute_count) = attributes.len().try_into() else {
return Err(io::const_io_error!(
ErrorKind::InvalidInput,
"maximum number of ProcThreadAttributes exceeded",
));
};
unsafe {
c::InitializeProcThreadAttributeList(
ptr::null_mut(),
attribute_count,
0,
&mut required_size,
)
};
let mut proc_thread_attribute_list = ProcThreadAttributeList(
vec![MaybeUninit::uninit(); required_size as usize].into_boxed_slice(),
);
// Once we've allocated the necessary memory, it's safe to invoke
// `InitializeProcThreadAttributeList` to properly initialize the list.
cvt(unsafe {
c::InitializeProcThreadAttributeList(
proc_thread_attribute_list.0.as_mut_ptr() as *mut _,
attribute_count,
0,
&mut required_size,
)
})?;
// # Add our attributes to the buffer.
// It's theoretically possible for the attribute count to exceed a u32 value.
// Therefore, we ensure that we don't add more attributes than the buffer was initialized for.
for (&attribute, value) in attributes.iter().take(attribute_count as usize) {
let value_ptr = &*value.data as *const (dyn Send + Sync) as _;
cvt(unsafe {
c::UpdateProcThreadAttribute(
proc_thread_attribute_list.0.as_mut_ptr() as _,
0,
attribute,
value_ptr,
value.size,
ptr::null_mut(),
ptr::null_mut(),
)
})?;
}
Ok(proc_thread_attribute_list)
}
pub struct CommandArgs<'a> { pub struct CommandArgs<'a> {
iter: crate::slice::Iter<'a, Arg>, iter: crate::slice::Iter<'a, Arg>,
} }

View File

@ -176,6 +176,14 @@ pub struct Instant(time::Instant);
/// The size of a `SystemTime` struct may vary depending on the target operating /// The size of a `SystemTime` struct may vary depending on the target operating
/// system. /// system.
/// ///
/// A `SystemTime` does not count leap seconds.
/// `SystemTime::now()`'s behaviour around a leap second
/// is the same as the operating system's wall clock.
/// The precise behaviour near a leap second
/// (e.g. whether the clock appears to run slow or fast, or stop, or jump)
/// depends on platform and configuration,
/// so should not be relied on.
///
/// Example: /// Example:
/// ///
/// ```no_run /// ```no_run
@ -461,6 +469,9 @@ impl fmt::Debug for Instant {
impl SystemTime { impl SystemTime {
/// An anchor in time which can be used to create new `SystemTime` instances or /// An anchor in time which can be used to create new `SystemTime` instances or
/// learn about where in time a `SystemTime` lies. /// learn about where in time a `SystemTime` lies.
//
// NOTE! this documentation is duplicated, here and in std::time::UNIX_EPOCH.
// The two copies are not quite identical, because of the difference in naming.
/// ///
/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with /// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with
/// respect to the system clock. Using `duration_since` on an existing /// respect to the system clock. Using `duration_since` on an existing
@ -468,6 +479,11 @@ impl SystemTime {
/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a /// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a
/// `SystemTime` instance to represent another fixed point in time. /// `SystemTime` instance to represent another fixed point in time.
/// ///
/// `duration_since(UNIX_EPOCH).unwrap().as_secs()` returns
/// the number of non-leap seconds since the start of 1970 UTC.
/// This is a POSIX `time_t` (as a `u64`),
/// and is the same time representation as used in many Internet protocols.
///
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
@ -617,6 +633,9 @@ impl fmt::Debug for SystemTime {
/// An anchor in time which can be used to create new `SystemTime` instances or /// An anchor in time which can be used to create new `SystemTime` instances or
/// learn about where in time a `SystemTime` lies. /// learn about where in time a `SystemTime` lies.
//
// NOTE! this documentation is duplicated, here and in SystemTime::UNIX_EPOCH.
// The two copies are not quite identical, because of the difference in naming.
/// ///
/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with /// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with
/// respect to the system clock. Using `duration_since` on an existing /// respect to the system clock. Using `duration_since` on an existing
@ -624,6 +643,11 @@ impl fmt::Debug for SystemTime {
/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a /// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a
/// [`SystemTime`] instance to represent another fixed point in time. /// [`SystemTime`] instance to represent another fixed point in time.
/// ///
/// `duration_since(UNIX_EPOCH).unwrap().as_secs()` returns
/// the number of non-leap seconds since the start of 1970 UTC.
/// This is a POSIX `time_t` (as a `u64`),
/// and is the same time representation as used in many Internet protocols.
///
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run

View File

@ -353,10 +353,17 @@ pub struct RustAnalyzer {
impl Step for RustAnalyzer { impl Step for RustAnalyzer {
type Output = (); type Output = ();
const ONLY_HOSTS: bool = true; const ONLY_HOSTS: bool = true;
const DEFAULT: bool = false; const DEFAULT: bool = true;
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.path("src/tools/rust-analyzer") let builder = run.builder;
run.path("src/tools/rust-analyzer").default_condition(
builder
.config
.tools
.as_ref()
.map_or(true, |tools| tools.iter().any(|tool| tool == "rust-analyzer")),
)
} }
fn make_run(run: RunConfig<'_>) { fn make_run(run: RunConfig<'_>) {

View File

@ -35,7 +35,7 @@ fn download_ci_llvm() {
)); ));
} }
// FIXME(ozkanonur): extend scope of the test // FIXME(onur-ozkan): extend scope of the test
// refs: // refs:
// - https://github.com/rust-lang/rust/issues/109120 // - https://github.com/rust-lang/rust/issues/109120
// - https://github.com/rust-lang/rust/pull/109162#issuecomment-1496782487 // - https://github.com/rust-lang/rust/pull/109162#issuecomment-1496782487

View File

@ -64,9 +64,8 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
docker --version >> $hash_key docker --version >> $hash_key
# Include cache version. Currently it is needed to bust Docker # Include cache version. Can be used to manually bust the Docker cache.
# cache key after opting in into the old Docker build backend. echo "2" >> $hash_key
echo "1" >> $hash_key
cksum=$(sha512sum $hash_key | \ cksum=$(sha512sum $hash_key | \
awk '{print $1}') awk '{print $1}')
@ -78,6 +77,10 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
set +e set +e
retry curl --max-time 600 -y 30 -Y 10 --connect-timeout 30 -f -L -C - \ retry curl --max-time 600 -y 30 -Y 10 --connect-timeout 30 -f -L -C - \
-o /tmp/rustci_docker_cache "$url" -o /tmp/rustci_docker_cache "$url"
docker_archive_hash=$(sha512sum /tmp/rustci_docker_cache | awk '{print $1}')
echo "Downloaded archive hash: ${docker_archive_hash}"
echo "Loading images into docker" echo "Loading images into docker"
# docker load sometimes hangs in the CI, so time out after 10 minutes with TERM, # docker load sometimes hangs in the CI, so time out after 10 minutes with TERM,
# KILL after 12 minutes # KILL after 12 minutes
@ -115,8 +118,10 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
digest=$(docker inspect rust-ci --format '{{.Id}}') digest=$(docker inspect rust-ci --format '{{.Id}}')
echo "Built container $digest" echo "Built container $digest"
if ! grep -q "$digest" <(echo "$loaded_images"); then if ! grep -q "$digest" <(echo "$loaded_images"); then
echo "Uploading finished image to $url" echo "Uploading finished image $digest to $url"
set +e set +e
# Print image history for easier debugging of layer SHAs
docker history rust-ci
docker history -q rust-ci | \ docker history -q rust-ci | \
grep -v missing | \ grep -v missing | \
xargs docker save | \ xargs docker save | \
@ -131,6 +136,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
mkdir -p "$dist" mkdir -p "$dist"
echo "$url" >"$info" echo "$url" >"$info"
echo "$digest" >>"$info" echo "$digest" >>"$info"
cat "$info"
fi fi
elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then elif [ -f "$docker_dir/disabled/$image/Dockerfile" ]; then
if isCI; then if isCI; then

View File

@ -313,7 +313,7 @@ target | std | host | notes
[`riscv64-linux-android`](platform-support/android.md) | | | RISC-V 64-bit Android [`riscv64-linux-android`](platform-support/android.md) | | | RISC-V 64-bit Android
`s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, MUSL) `s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, MUSL)
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
[`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | Bare 32-bit SPARC V7+ [`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | | Bare 32-bit SPARC V7+
[`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64 [`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64
[`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64
`thumbv4t-none-eabi` | * | | Thumb-mode Bare ARMv4T `thumbv4t-none-eabi` | * | | Thumb-mode Bare ARMv4T

View File

@ -400,7 +400,12 @@ constructs. For example, a macro use `foo!(a, b, c)` can be parsed like a
function call (ignoring the `!`), so format it using the rules for function function call (ignoring the `!`), so format it using the rules for function
calls. calls.
### Special case macros The style guide defines specific formatting for particular macros in the
language or standard library. The style guide does not define formatting for
any third-party macros, even if similar to those in the language or standard
library.
### Format string macros
For macros which take a format string, if all other arguments are *small*, For macros which take a format string, if all other arguments are *small*,
format the arguments before the format string on a single line if they fit, and format the arguments before the format string on a single line if they fit, and

View File

@ -55,9 +55,9 @@ RUST_GDBGUI="${RUST_GDBGUI:-gdbgui}"
# These arguments get passed through to GDB and make it load the # These arguments get passed through to GDB and make it load the
# Rust pretty printers. # Rust pretty printers.
GDB_ARGS="--directory=\"$GDB_PYTHON_MODULE_DIRECTORY\"" \ GDB_ARGS="--directory=\"$GDB_PYTHON_MODULE_DIRECTORY\" \
"-iex \"add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY\"" \ -iex \"add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY\" \
"-iex \"set substitute-path /rustc/$RUSTC_COMMIT_HASH $RUSTC_SYSROOT/lib/rustlib/src/rust\"" -iex \"set substitute-path /rustc/$RUSTC_COMMIT_HASH $RUSTC_SYSROOT/lib/rustlib/src/rust\""
# Finally we execute gdbgui. # Finally we execute gdbgui.
PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" \ PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" \

View File

@ -31,7 +31,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--codeblock-error-color: rgba(255, 0, 0, .5); --codeblock-error-color: rgba(255, 0, 0, .5);
--codeblock-ignore-hover-color: rgb(255, 142, 0); --codeblock-ignore-hover-color: rgb(255, 142, 0);
--codeblock-ignore-color: rgba(255, 142, 0, .6); --codeblock-ignore-color: rgba(255, 142, 0, .6);
--warning-border-color: rgb(255, 142, 0); --warning-border-color: #ff8e00;
--type-link-color: #ffa0a5; --type-link-color: #ffa0a5;
--trait-link-color: #39afd7; --trait-link-color: #39afd7;
--assoc-item-link-color: #39afd7; --assoc-item-link-color: #39afd7;
@ -96,8 +96,8 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--codeblock-link-background: #333; --codeblock-link-background: #333;
--scrape-example-toggle-line-background: #999; --scrape-example-toggle-line-background: #999;
--scrape-example-toggle-line-hover-background: #c5c5c5; --scrape-example-toggle-line-hover-background: #c5c5c5;
--scrape-example-code-line-highlight: rgb(91, 59, 1); --scrape-example-code-line-highlight: #5b3b01;
--scrape-example-code-line-highlight-focus: rgb(124, 75, 15); --scrape-example-code-line-highlight-focus: #7c4b0f;
--scrape-example-help-border-color: #aaa; --scrape-example-help-border-color: #aaa;
--scrape-example-help-color: #eee; --scrape-example-help-color: #eee;
--scrape-example-help-hover-border-color: #fff; --scrape-example-help-hover-border-color: #fff;

View File

@ -26,7 +26,7 @@
--codeblock-error-color: rgba(255, 0, 0, .5); --codeblock-error-color: rgba(255, 0, 0, .5);
--codeblock-ignore-hover-color: rgb(255, 142, 0); --codeblock-ignore-hover-color: rgb(255, 142, 0);
--codeblock-ignore-color: rgba(255, 142, 0, .6); --codeblock-ignore-color: rgba(255, 142, 0, .6);
--warning-border-color: rgb(255, 142, 0); --warning-border-color: #ff8e00;
--type-link-color: #2dbfb8; --type-link-color: #2dbfb8;
--trait-link-color: #b78cf2; --trait-link-color: #b78cf2;
--assoc-item-link-color: #d2991d; --assoc-item-link-color: #d2991d;
@ -69,7 +69,7 @@
--test-arrow-color: #dedede; --test-arrow-color: #dedede;
--test-arrow-background-color: rgba(78, 139, 202, 0.2); --test-arrow-background-color: rgba(78, 139, 202, 0.2);
--test-arrow-hover-color: #dedede; --test-arrow-hover-color: #dedede;
--test-arrow-hover-background-color: rgb(78, 139, 202); --test-arrow-hover-background-color: #4e8bca;
--target-background-color: #494a3d; --target-background-color: #494a3d;
--target-border-color: #bb7410; --target-border-color: #bb7410;
--kbd-color: #000; --kbd-color: #000;
@ -87,12 +87,12 @@
--crate-search-hover-border: #2196f3; --crate-search-hover-border: #2196f3;
--src-sidebar-background-selected: #333; --src-sidebar-background-selected: #333;
--src-sidebar-background-hover: #444; --src-sidebar-background-hover: #444;
--table-alt-row-background-color: #2A2A2A; --table-alt-row-background-color: #2a2a2a;
--codeblock-link-background: #333; --codeblock-link-background: #333;
--scrape-example-toggle-line-background: #999; --scrape-example-toggle-line-background: #999;
--scrape-example-toggle-line-hover-background: #c5c5c5; --scrape-example-toggle-line-hover-background: #c5c5c5;
--scrape-example-code-line-highlight: rgb(91, 59, 1); --scrape-example-code-line-highlight: #5b3b01;
--scrape-example-code-line-highlight-focus: rgb(124, 75, 15); --scrape-example-code-line-highlight-focus: #7c4b0f;
--scrape-example-help-border-color: #aaa; --scrape-example-help-border-color: #aaa;
--scrape-example-help-color: #eee; --scrape-example-help-color: #eee;
--scrape-example-help-hover-border-color: #fff; --scrape-example-help-hover-border-color: #fff;

View File

@ -5,9 +5,9 @@
--settings-input-border-color: #717171; --settings-input-border-color: #717171;
--settings-button-color: #000; --settings-button-color: #000;
--settings-button-border-focus: #717171; --settings-button-border-focus: #717171;
--sidebar-background-color: #F5F5F5; --sidebar-background-color: #f5f5f5;
--sidebar-background-color-hover: #E0E0E0; --sidebar-background-color-hover: #e0e0e0;
--code-block-background-color: #F5F5F5; --code-block-background-color: #f5f5f5;
--scrollbar-track-background-color: #dcdcdc; --scrollbar-track-background-color: #dcdcdc;
--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6); --scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
--scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9; --scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
@ -26,7 +26,7 @@
--codeblock-error-color: rgba(255, 0, 0, .5); --codeblock-error-color: rgba(255, 0, 0, .5);
--codeblock-ignore-hover-color: rgb(255, 142, 0); --codeblock-ignore-hover-color: rgb(255, 142, 0);
--codeblock-ignore-color: rgba(255, 142, 0, .6); --codeblock-ignore-color: rgba(255, 142, 0, .6);
--warning-border-color: rgb(255, 142, 0); --warning-border-color: #ff8e00;
--type-link-color: #ad378a; --type-link-color: #ad378a;
--trait-link-color: #6e4fc9; --trait-link-color: #6e4fc9;
--assoc-item-link-color: #3873ad; --assoc-item-link-color: #3873ad;
@ -47,7 +47,7 @@
--search-tab-button-not-selected-border-top-color: #e6e6e6; --search-tab-button-not-selected-border-top-color: #e6e6e6;
--search-tab-button-not-selected-background: #e6e6e6; --search-tab-button-not-selected-background: #e6e6e6;
--search-tab-button-selected-border-top-color: #0089ff; --search-tab-button-selected-border-top-color: #0089ff;
--search-tab-button-selected-background: #ffffff; --search-tab-button-selected-background: #fff;
--stab-background-color: #fff5d6; --stab-background-color: #fff5d6;
--stab-code-color: #000; --stab-code-color: #000;
--code-highlight-kw-color: #8959a8; --code-highlight-kw-color: #8959a8;
@ -84,7 +84,7 @@
--crate-search-hover-border: #717171; --crate-search-hover-border: #717171;
--src-sidebar-background-selected: #fff; --src-sidebar-background-selected: #fff;
--src-sidebar-background-hover: #e0e0e0; --src-sidebar-background-hover: #e0e0e0;
--table-alt-row-background-color: #F5F5F5; --table-alt-row-background-color: #f5f5f5;
--codeblock-link-background: #eee; --codeblock-link-background: #eee;
--scrape-example-toggle-line-background: #ccc; --scrape-example-toggle-line-background: #ccc;
--scrape-example-toggle-line-hover-background: #999; --scrape-example-toggle-line-hover-background: #999;

@ -1 +1 @@
Subproject commit 2cc50bc0b63ad20da193e002ba11d391af0104b7 Subproject commit 925280f028db3a322935e040719a0754703947cf

View File

@ -1 +1 @@
9334ec93541fd6963a3bfa2d2d09e3e33ac93131 f3284dc3ad9254236d296daa1285dd273b492b01

Some files were not shown because too many files have changed in this diff Show More