mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 15:23:46 +00:00
Auto merge of #3042 - rust-lang:rustup-2023-08-29, r=RalfJung
Automatic sync from rustc
This commit is contained in:
commit
d9c11c65ee
@ -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,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -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) => {
|
||||||
|
@ -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,
|
||||||
|
|
||||||
|
@ -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(_), .. } => {
|
||||||
|
@ -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 }
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
||||||
|
@ -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,
|
||||||
|
@ -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)| {
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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()
|
||||||
{
|
{
|
||||||
|
@ -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,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
|
||||||
|
@ -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.).
|
||||||
|
@ -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!(
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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() {
|
||||||
|
@ -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),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -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>`
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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";
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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 ()>>()];
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
{
|
{
|
||||||
|
@ -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);
|
||||||
|
@ -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)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")]
|
||||||
|
@ -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}
|
||||||
|
|
||||||
|
93
compiler/rustc_passes/src/abi_test.rs
Normal file
93
compiler/rustc_passes/src/abi_test.rs
Normal 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:?}",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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)]
|
||||||
|
@ -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| {
|
||||||
|
@ -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;
|
||||||
|
@ -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());
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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],
|
||||||
|
@ -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)]
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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)]
|
||||||
|
@ -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",
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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('>');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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"),
|
||||||
|
@ -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,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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`
|
||||||
|
@ -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)]
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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")]
|
||||||
|
@ -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")]
|
||||||
|
@ -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.
|
||||||
|
@ -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 {
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
///
|
///
|
||||||
|
@ -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
|
||||||
|
@ -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() {
|
||||||
|
@ -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")]
|
||||||
|
@ -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
|
||||||
|
@ -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) {}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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]
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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>,
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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<'_>) {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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" \
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
@ -1 +1 @@
|
|||||||
9334ec93541fd6963a3bfa2d2d09e3e33ac93131
|
f3284dc3ad9254236d296daa1285dd273b492b01
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user