commit
b7912d38b1
5902 changed files with 7653 additions and 6350 deletions
12
Cargo.lock
12
Cargo.lock
|
@ -5767,9 +5767,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.6.0"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
|
||||
checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
@ -6072,9 +6072,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-bindgen"
|
||||
version = "0.51.1"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc1f16b778125675feee0d15d6dd9f6af0e3ac52b3233d63a10aa39230c1cd75"
|
||||
checksum = "970efb0b6849eb8a87a898f586af7cc167567b070014c7434514c0bde0ca341c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"rayon",
|
||||
|
@ -6084,9 +6084,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "windows-metadata"
|
||||
version = "0.51.1"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "753135d996f9da437c0b31dbde3032489a61708361929bcc07d4fba0b161000e"
|
||||
checksum = "218fd59201e26acdbb894fa2b302d1de84bf3eec7d0eb894ac8e9c5a854ee4ef"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
|
|
|
@ -301,7 +301,7 @@ pub enum TraitBoundModifier {
|
|||
Maybe,
|
||||
|
||||
/// `~const Trait`
|
||||
MaybeConst,
|
||||
MaybeConst(Span),
|
||||
|
||||
/// `~const !Trait`
|
||||
//
|
||||
|
@ -317,8 +317,7 @@ pub enum TraitBoundModifier {
|
|||
impl TraitBoundModifier {
|
||||
pub fn to_constness(self) -> Const {
|
||||
match self {
|
||||
// FIXME(effects) span
|
||||
Self::MaybeConst => Const::Yes(DUMMY_SP),
|
||||
Self::MaybeConst(span) => Const::Yes(span),
|
||||
_ => Const::No,
|
||||
}
|
||||
}
|
||||
|
@ -3155,7 +3154,7 @@ mod size_asserts {
|
|||
static_assert_size!(ForeignItem, 96);
|
||||
static_assert_size!(ForeignItemKind, 24);
|
||||
static_assert_size!(GenericArg, 24);
|
||||
static_assert_size!(GenericBound, 56);
|
||||
static_assert_size!(GenericBound, 64);
|
||||
static_assert_size!(Generics, 40);
|
||||
static_assert_size!(Impl, 136);
|
||||
static_assert_size!(Item, 136);
|
||||
|
|
|
@ -1369,7 +1369,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
GenericBound::Trait(
|
||||
ty,
|
||||
modifier @ (TraitBoundModifier::None
|
||||
| TraitBoundModifier::MaybeConst
|
||||
| TraitBoundModifier::MaybeConst(_)
|
||||
| TraitBoundModifier::Negative),
|
||||
) => {
|
||||
Some(this.lower_poly_trait_ref(ty, itctx, modifier.to_constness()))
|
||||
|
@ -2227,7 +2227,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
fn lower_trait_bound_modifier(&mut self, f: TraitBoundModifier) -> hir::TraitBoundModifier {
|
||||
match f {
|
||||
TraitBoundModifier::None => hir::TraitBoundModifier::None,
|
||||
TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst,
|
||||
TraitBoundModifier::MaybeConst(_) => hir::TraitBoundModifier::MaybeConst,
|
||||
|
||||
TraitBoundModifier::Negative => {
|
||||
if self.tcx.features().negative_bounds {
|
||||
|
|
|
@ -1203,7 +1203,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
(BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
|
||||
self.err_handler().emit_err(errors::OptionalTraitObject { span: poly.span });
|
||||
}
|
||||
(_, TraitBoundModifier::MaybeConst)
|
||||
(_, &TraitBoundModifier::MaybeConst(span))
|
||||
if let Some(reason) = &self.disallow_tilde_const =>
|
||||
{
|
||||
let reason = match reason {
|
||||
|
@ -1224,8 +1224,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
DisallowTildeConstContext::Item => errors::TildeConstReason::Item,
|
||||
};
|
||||
self.err_handler()
|
||||
.emit_err(errors::TildeConstDisallowed { span: bound.span(), reason });
|
||||
self.err_handler().emit_err(errors::TildeConstDisallowed { span, reason });
|
||||
}
|
||||
(_, TraitBoundModifier::MaybeConstMaybe) => {
|
||||
self.err_handler().emit_err(errors::OptionalConstExclusive {
|
||||
|
|
|
@ -1515,7 +1515,7 @@ impl<'a> State<'a> {
|
|||
TraitBoundModifier::Maybe => {
|
||||
self.word("?");
|
||||
}
|
||||
TraitBoundModifier::MaybeConst => {
|
||||
TraitBoundModifier::MaybeConst(_) => {
|
||||
self.word_space("~const");
|
||||
}
|
||||
TraitBoundModifier::MaybeConstNegative => {
|
||||
|
|
|
@ -127,18 +127,17 @@ fn extract_default_variant<'a>(
|
|||
[first, rest @ ..] => {
|
||||
let suggs = default_variants
|
||||
.iter()
|
||||
.map(|variant| {
|
||||
let spans = default_variants
|
||||
.filter_map(|variant| {
|
||||
let keep = attr::find_by_name(&variant.attrs, kw::Default)?.span;
|
||||
let spans: Vec<Span> = default_variants
|
||||
.iter()
|
||||
.filter_map(|v| {
|
||||
if v.span == variant.span {
|
||||
None
|
||||
} else {
|
||||
Some(attr::find_by_name(&v.attrs, kw::Default)?.span)
|
||||
}
|
||||
.flat_map(|v| {
|
||||
attr::filter_by_name(&v.attrs, kw::Default)
|
||||
.filter_map(|attr| (attr.span != keep).then_some(attr.span))
|
||||
})
|
||||
.collect();
|
||||
errors::MultipleDefaultsSugg { spans, ident: variant.ident }
|
||||
(!spans.is_empty())
|
||||
.then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident })
|
||||
})
|
||||
.collect();
|
||||
cx.emit_err(errors::MultipleDefaults {
|
||||
|
|
|
@ -100,6 +100,15 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[
|
|||
TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
|
||||
TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"),
|
||||
TestCase::build_bin_and_run("aot.neon", "example/neon.rs", &[]),
|
||||
TestCase::custom("aot.gen_block_iterate", &|runner| {
|
||||
runner.run_rustc([
|
||||
"example/gen_block_iterate.rs",
|
||||
"--edition",
|
||||
"2024",
|
||||
"-Zunstable-options",
|
||||
]);
|
||||
runner.run_out_command("gen_block_iterate", &[]);
|
||||
}),
|
||||
];
|
||||
|
||||
pub(crate) static RAND_REPO: GitRepo = GitRepo::github(
|
||||
|
|
|
@ -43,6 +43,7 @@ aot.mod_bench
|
|||
aot.issue-72793
|
||||
aot.issue-59326
|
||||
aot.neon
|
||||
aot.gen_block_iterate
|
||||
|
||||
testsuite.extended_sysroot
|
||||
test.rust-random/rand
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// Copied from https://github.com/rust-lang/rust/blob/46455dc65069387f2dc46612f13fd45452ab301a/tests/ui/coroutine/gen_block_iterate.rs
|
||||
// revisions: next old
|
||||
//compile-flags: --edition 2024 -Zunstable-options
|
||||
//[next] compile-flags: -Ztrait-solver=next
|
||||
// run-pass
|
||||
#![feature(gen_blocks)]
|
||||
|
||||
fn foo() -> impl Iterator<Item = u32> {
|
||||
gen { yield 42; for x in 3..6 { yield x } }
|
||||
}
|
||||
|
||||
fn moved() -> impl Iterator<Item = u32> {
|
||||
let mut x = "foo".to_string();
|
||||
gen move {
|
||||
yield 42;
|
||||
if x == "foo" { return }
|
||||
x.clear();
|
||||
for x in 3..6 { yield x }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut iter = foo();
|
||||
assert_eq!(iter.next(), Some(42));
|
||||
assert_eq!(iter.next(), Some(3));
|
||||
assert_eq!(iter.next(), Some(4));
|
||||
assert_eq!(iter.next(), Some(5));
|
||||
assert_eq!(iter.next(), None);
|
||||
// `gen` blocks are fused
|
||||
assert_eq!(iter.next(), None);
|
||||
|
||||
let mut iter = moved();
|
||||
assert_eq!(iter.next(), Some(42));
|
||||
assert_eq!(iter.next(), None);
|
||||
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
ignore = ["y.rs"]
|
||||
ignore = [
|
||||
"y.rs",
|
||||
"example/gen_block_iterate.rs", # uses edition 2024
|
||||
]
|
||||
|
||||
# Matches rustfmt.toml of rustc
|
||||
version = "Two"
|
||||
|
|
|
@ -501,6 +501,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
/// This function is used by Miri's provenance GC to remove unreachable entries from the dead_alloc_map.
|
||||
pub fn remove_unreachable_allocs(&mut self, reachable_allocs: &FxHashSet<AllocId>) {
|
||||
// Unlike all the other GC helpers where we check if an `AllocId` is found in the interpreter or
|
||||
// is live, here all the IDs in the map are for dead allocations so we don't
|
||||
// need to check for liveness.
|
||||
#[allow(rustc::potential_query_instability)] // Only used from Miri, not queries.
|
||||
self.memory.dead_alloc_map.retain(|id, _| reachable_allocs.contains(id));
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocation accessors
|
||||
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
/// Helper function to obtain a global (tcx) allocation.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use parking_lot::Mutex;
|
||||
use std::cell::Cell;
|
||||
use std::cell::OnceCell;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::ops::Deref;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
@ -30,7 +31,7 @@ impl RegistryId {
|
|||
}
|
||||
|
||||
struct RegistryData {
|
||||
thread_limit: usize,
|
||||
thread_limit: NonZeroUsize,
|
||||
threads: Mutex<usize>,
|
||||
}
|
||||
|
||||
|
@ -60,7 +61,7 @@ thread_local! {
|
|||
|
||||
impl Registry {
|
||||
/// Creates a registry which can hold up to `thread_limit` threads.
|
||||
pub fn new(thread_limit: usize) -> Self {
|
||||
pub fn new(thread_limit: NonZeroUsize) -> Self {
|
||||
Registry(Arc::new(RegistryData { thread_limit, threads: Mutex::new(0) }))
|
||||
}
|
||||
|
||||
|
@ -73,7 +74,7 @@ impl Registry {
|
|||
/// Panics if the thread limit is hit or if the thread already has an associated registry.
|
||||
pub fn register(&self) {
|
||||
let mut threads = self.0.threads.lock();
|
||||
if *threads < self.0.thread_limit {
|
||||
if *threads < self.0.thread_limit.get() {
|
||||
REGISTRY.with(|registry| {
|
||||
if registry.get().is_some() {
|
||||
drop(threads);
|
||||
|
@ -126,7 +127,9 @@ impl<T> WorkerLocal<T> {
|
|||
{
|
||||
let registry = Registry::current();
|
||||
WorkerLocal {
|
||||
locals: (0..registry.0.thread_limit).map(|i| CacheAligned(initial(i))).collect(),
|
||||
locals: (0..registry.0.thread_limit.get())
|
||||
.map(|i| CacheAligned(initial(i)))
|
||||
.collect(),
|
||||
registry,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1465,7 +1465,7 @@ impl HandlerInner {
|
|||
};
|
||||
let errors = match self.deduplicated_err_count {
|
||||
0 => Cow::from(""),
|
||||
1 => Cow::from("aborting due to previous error"),
|
||||
1 => Cow::from("aborting due to 1 previous error"),
|
||||
count => Cow::from(format!("aborting due to {count} previous errors")),
|
||||
};
|
||||
if self.treat_err_as_bug() {
|
||||
|
|
|
@ -4,7 +4,7 @@ use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, LocalKind, PatKind,
|
|||
use rustc_ast::{attr, token, util::literal};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
impl<'a> ExtCtxt<'a> {
|
||||
|
@ -135,7 +135,7 @@ impl<'a> ExtCtxt<'a> {
|
|||
ast::GenericBound::Trait(
|
||||
self.poly_trait_ref(path.span, path),
|
||||
if is_const {
|
||||
ast::TraitBoundModifier::MaybeConst
|
||||
ast::TraitBoundModifier::MaybeConst(DUMMY_SP)
|
||||
} else {
|
||||
ast::TraitBoundModifier::None
|
||||
},
|
||||
|
|
|
@ -160,7 +160,7 @@ declare_features! (
|
|||
// no-tracking-issue-start
|
||||
|
||||
/// Allows using the `unadjusted` ABI; perma-unstable.
|
||||
(unstable, abi_unadjusted, "1.16.0", None, None),
|
||||
(internal, abi_unadjusted, "1.16.0", None, None),
|
||||
/// Allows using the `vectorcall` ABI.
|
||||
(unstable, abi_vectorcall, "1.7.0", None, None),
|
||||
/// Allows using `#![needs_allocator]`, an implementation detail of `#[global_allocator]`.
|
||||
|
@ -456,6 +456,8 @@ declare_features! (
|
|||
(unstable, ffi_returns_twice, "1.34.0", Some(58314), None),
|
||||
/// Allows using `#[repr(align(...))]` on function items
|
||||
(unstable, fn_align, "1.53.0", Some(82232), None),
|
||||
/// Support delegating implementation of functions to other already implemented functions.
|
||||
(incomplete, fn_delegation, "CURRENT_RUSTC_VERSION", Some(118212), None),
|
||||
/// Allows defining gen blocks and `gen fn`.
|
||||
(unstable, gen_blocks, "1.75.0", Some(117078), None),
|
||||
/// Infer generic args for both consts and types.
|
||||
|
|
|
@ -526,14 +526,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
_ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0,
|
||||
};
|
||||
|
||||
if let ty::FnDef(did, callee_args) = *ty.kind() {
|
||||
if let ty::FnDef(did, _) = *ty.kind() {
|
||||
let fn_sig = ty.fn_sig(tcx);
|
||||
|
||||
// HACK: whenever we get a FnDef in a non-const context, enforce effects to get the
|
||||
// default `host = true` to avoid inference errors later.
|
||||
if tcx.hir().body_const_context(self.body_id).is_none() {
|
||||
self.enforce_context_effects(expr.hir_id, qpath.span(), did, callee_args);
|
||||
}
|
||||
if tcx.fn_sig(did).skip_binder().abi() == RustIntrinsic
|
||||
&& tcx.item_name(did) == sym::transmute
|
||||
{
|
||||
|
@ -1932,7 +1927,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// 8 | foo::Foo {};
|
||||
/// | ^^^^^^^^ missing `you_can_use_this_field`
|
||||
///
|
||||
/// error: aborting due to previous error
|
||||
/// error: aborting due to 1 previous error
|
||||
/// ```
|
||||
fn report_missing_fields(
|
||||
&self,
|
||||
|
@ -2049,7 +2044,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
/// 8 | foo::Foo {};
|
||||
/// | ^^^^^^^^
|
||||
///
|
||||
/// error: aborting due to previous error
|
||||
/// error: aborting due to 1 previous error
|
||||
/// ```
|
||||
fn report_private_fields(
|
||||
&self,
|
||||
|
|
|
@ -9,7 +9,6 @@ use crate::infer::canonical::{
|
|||
Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
|
||||
};
|
||||
use crate::infer::InferCtxt;
|
||||
use rustc_middle::ty::flags::FlagComputation;
|
||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
|
||||
use rustc_middle::ty::GenericArg;
|
||||
use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
|
||||
|
@ -550,8 +549,11 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
let flags = FlagComputation::for_const(ct);
|
||||
if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { ct }
|
||||
if ct.flags().intersects(self.needs_canonical_flags) {
|
||||
ct.super_fold_with(self)
|
||||
} else {
|
||||
ct
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
|
|||
use rustc_query_impl::QueryCtxt;
|
||||
use rustc_query_system::query::{deadlock, QueryContext};
|
||||
|
||||
let registry = sync::Registry::new(threads);
|
||||
let registry = sync::Registry::new(std::num::NonZeroUsize::new(threads).unwrap());
|
||||
|
||||
if !sync::is_dyn_thread_safe() {
|
||||
return run_in_thread_with_globals(edition, || {
|
||||
|
|
|
@ -491,8 +491,9 @@ lint_requested_level = requested on the command line with `{$level} {$lint_name}
|
|||
lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
|
||||
|
||||
lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion
|
||||
.label = `{$self_ty}` implements `Deref<Target = dyn {$target_principal}>` which conflicts with supertrait `{$supertrait_principal}`
|
||||
.label2 = target type is a supertrait of `{$self_ty}`
|
||||
.help = consider removing this implementation or replacing it with a method instead
|
||||
.label = target type is a supertrait of `{$t}`
|
||||
|
||||
lint_suspicious_double_ref_clone =
|
||||
using `.clone()` on a double reference, which returns `{$ty}` instead of cloning the inner type
|
||||
|
|
|
@ -53,35 +53,43 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
|
|||
let tcx = cx.tcx;
|
||||
// `Deref` is being implemented for `t`
|
||||
if let hir::ItemKind::Impl(impl_) = item.kind
|
||||
// the trait is a `Deref` implementation
|
||||
&& let Some(trait_) = &impl_.of_trait
|
||||
&& let t = tcx.type_of(item.owner_id).instantiate_identity()
|
||||
&& let opt_did @ Some(did) = trait_.trait_def_id()
|
||||
&& opt_did == tcx.lang_items().deref_trait()
|
||||
// `t` is `dyn t_principal`
|
||||
&& let ty::Dynamic(data, _, ty::Dyn) = t.kind()
|
||||
&& let Some(t_principal) = data.principal()
|
||||
&& let Some(did) = trait_.trait_def_id()
|
||||
&& Some(did) == tcx.lang_items().deref_trait()
|
||||
// the self type is `dyn t_principal`
|
||||
&& let self_ty = tcx.type_of(item.owner_id).instantiate_identity()
|
||||
&& let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind()
|
||||
&& let Some(self_principal) = data.principal()
|
||||
// `<T as Deref>::Target` is `dyn target_principal`
|
||||
&& let Some(target) = cx.get_associated_type(t, did, "Target")
|
||||
&& let Some(target) = cx.get_associated_type(self_ty, did, "Target")
|
||||
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
|
||||
&& let Some(target_principal) = data.principal()
|
||||
// `target_principal` is a supertrait of `t_principal`
|
||||
&& supertraits(tcx, t_principal.with_self_ty(tcx, tcx.types.trait_object_dummy_self))
|
||||
.any(|sup| {
|
||||
tcx.erase_regions(
|
||||
sup.map_bound(|x| ty::ExistentialTraitRef::erase_self_ty(tcx, x)),
|
||||
) == tcx.erase_regions(target_principal)
|
||||
})
|
||||
&& let Some(supertrait_principal) = supertraits(tcx, self_principal.with_self_ty(tcx, self_ty))
|
||||
.find(|supertrait| supertrait.def_id() == target_principal.def_id())
|
||||
{
|
||||
let t = tcx.erase_regions(t);
|
||||
let label = impl_
|
||||
// erase regions in self type for better diagnostic presentation
|
||||
let (self_ty, target_principal, supertrait_principal) =
|
||||
tcx.erase_regions((self_ty, target_principal, supertrait_principal));
|
||||
let label2 = impl_
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|i| (i.ident.name == sym::Target).then_some(i.span))
|
||||
.map(|label| SupertraitAsDerefTargetLabel { label });
|
||||
let span = tcx.def_span(item.owner_id.def_id);
|
||||
cx.emit_spanned_lint(
|
||||
DEREF_INTO_DYN_SUPERTRAIT,
|
||||
tcx.def_span(item.owner_id.def_id),
|
||||
SupertraitAsDerefTarget { t, label },
|
||||
span,
|
||||
SupertraitAsDerefTarget {
|
||||
self_ty,
|
||||
supertrait_principal: supertrait_principal.map_bound(|trait_ref| {
|
||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
|
||||
}),
|
||||
target_principal,
|
||||
label: span,
|
||||
label2,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@ use rustc_errors::{
|
|||
};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_macros::{LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::{inhabitedness::InhabitedPredicate, Clause, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{
|
||||
inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt,
|
||||
};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol};
|
||||
|
||||
|
@ -556,13 +558,17 @@ pub enum BuiltinSpecialModuleNameUsed {
|
|||
#[diag(lint_supertrait_as_deref_target)]
|
||||
#[help]
|
||||
pub struct SupertraitAsDerefTarget<'a> {
|
||||
pub t: Ty<'a>,
|
||||
pub self_ty: Ty<'a>,
|
||||
pub supertrait_principal: PolyExistentialTraitRef<'a>,
|
||||
pub target_principal: PolyExistentialTraitRef<'a>,
|
||||
#[label]
|
||||
pub label: Span,
|
||||
#[subdiagnostic]
|
||||
pub label: Option<SupertraitAsDerefTargetLabel>,
|
||||
pub label2: Option<SupertraitAsDerefTargetLabel>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[label(lint_label)]
|
||||
#[label(lint_label2)]
|
||||
pub struct SupertraitAsDerefTargetLabel {
|
||||
#[primary_span]
|
||||
pub label: Span,
|
||||
|
|
|
@ -94,7 +94,7 @@ macro_rules! arena_types {
|
|||
|
||||
// Interned types
|
||||
[] tys: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::TyKind<'tcx>>,
|
||||
[] consts: rustc_middle::ty::ConstData<'tcx>,
|
||||
[] consts: rustc_type_ir::WithCachedTypeInfo<rustc_middle::ty::ConstData<'tcx>>,
|
||||
|
||||
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
|
||||
// since we need to allocate this type on both the `rustc_hir` arena
|
||||
|
|
|
@ -61,7 +61,6 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
|||
use rustc_data_structures::steal::Steal;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_data_structures::sync::WorkerLocal;
|
||||
use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
|
|
|
@ -11,6 +11,7 @@ use field_offset::FieldOffset;
|
|||
use measureme::StringId;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::sync::AtomicU64;
|
||||
use rustc_data_structures::sync::WorkerLocal;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::hir_id::OwnerId;
|
||||
|
@ -71,7 +72,7 @@ pub struct QuerySystemFns<'tcx> {
|
|||
|
||||
pub struct QuerySystem<'tcx> {
|
||||
pub states: QueryStates<'tcx>,
|
||||
pub arenas: QueryArenas<'tcx>,
|
||||
pub arenas: WorkerLocal<QueryArenas<'tcx>>,
|
||||
pub caches: QueryCaches<'tcx>,
|
||||
pub dynamic_queries: DynamicQueries<'tcx>,
|
||||
|
||||
|
@ -370,7 +371,7 @@ macro_rules! define_callbacks {
|
|||
|
||||
pub struct QueryArenas<'tcx> {
|
||||
$($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*]
|
||||
(WorkerLocal<TypedArena<<$V as Deref>::Target>>)
|
||||
(TypedArena<<$V as Deref>::Target>)
|
||||
()
|
||||
),)*
|
||||
}
|
||||
|
@ -379,7 +380,7 @@ macro_rules! define_callbacks {
|
|||
fn default() -> Self {
|
||||
Self {
|
||||
$($name: query_if_arena!([$($modifiers)*]
|
||||
(WorkerLocal::new(|_| Default::default()))
|
||||
(Default::default())
|
||||
()
|
||||
),)*
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_type_ir::{TypeFlags, WithCachedTypeInfo};
|
||||
|
||||
mod int;
|
||||
mod kind;
|
||||
|
@ -23,7 +24,7 @@ use super::sty::ConstKind;
|
|||
/// Use this rather than `ConstData`, whenever possible.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
|
||||
#[rustc_pass_by_value]
|
||||
pub struct Const<'tcx>(pub(super) Interned<'tcx, ConstData<'tcx>>);
|
||||
pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>);
|
||||
|
||||
/// Typed constant value.
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
|
||||
|
@ -46,6 +47,16 @@ impl<'tcx> Const<'tcx> {
|
|||
self.0.kind.clone()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn flags(self) -> TypeFlags {
|
||||
self.0.flags
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
|
||||
self.0.outer_exclusive_binder
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new(tcx: TyCtxt<'tcx>, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
|
||||
tcx.mk_ct_from_kind(kind, ty)
|
||||
|
|
|
@ -151,7 +151,7 @@ pub struct CtxtInterners<'tcx> {
|
|||
clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
|
||||
projs: InternedSet<'tcx, List<ProjectionKind>>,
|
||||
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
|
||||
const_: InternedSet<'tcx, ConstData<'tcx>>,
|
||||
const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>,
|
||||
const_allocation: InternedSet<'tcx, Allocation>,
|
||||
bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
|
||||
layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>,
|
||||
|
@ -212,6 +212,32 @@ impl<'tcx> CtxtInterners<'tcx> {
|
|||
))
|
||||
}
|
||||
|
||||
/// Interns a const. (Use `mk_*` functions instead, where possible.)
|
||||
#[allow(rustc::usage_of_ty_tykind)]
|
||||
#[inline(never)]
|
||||
fn intern_const(
|
||||
&self,
|
||||
data: ty::ConstData<'tcx>,
|
||||
sess: &Session,
|
||||
untracked: &Untracked,
|
||||
) -> Const<'tcx> {
|
||||
Const(Interned::new_unchecked(
|
||||
self.const_
|
||||
.intern(data, |data: ConstData<'_>| {
|
||||
let flags = super::flags::FlagComputation::for_const(&data.kind, data.ty);
|
||||
let stable_hash = self.stable_hash(&flags, sess, untracked, &data);
|
||||
|
||||
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
|
||||
internee: data,
|
||||
stable_hash,
|
||||
flags: flags.flags,
|
||||
outer_exclusive_binder: flags.outer_exclusive_binder,
|
||||
}))
|
||||
})
|
||||
.0,
|
||||
))
|
||||
}
|
||||
|
||||
fn stable_hash<'a, T: HashStable<StableHashingContext<'a>>>(
|
||||
&self,
|
||||
flags: &ty::flags::FlagComputation,
|
||||
|
@ -418,11 +444,17 @@ impl<'tcx> CommonLifetimes<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> CommonConsts<'tcx> {
|
||||
fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonConsts<'tcx> {
|
||||
fn new(
|
||||
interners: &CtxtInterners<'tcx>,
|
||||
types: &CommonTypes<'tcx>,
|
||||
sess: &Session,
|
||||
untracked: &Untracked,
|
||||
) -> CommonConsts<'tcx> {
|
||||
let mk_const = |c| {
|
||||
Const(Interned::new_unchecked(
|
||||
interners.const_.intern(c, |c| InternedInSet(interners.arena.alloc(c))).0,
|
||||
))
|
||||
interners.intern_const(
|
||||
c, sess, // This is only used to create a stable hashing context.
|
||||
untracked,
|
||||
)
|
||||
};
|
||||
|
||||
CommonConsts {
|
||||
|
@ -714,7 +746,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
let interners = CtxtInterners::new(arena);
|
||||
let common_types = CommonTypes::new(&interners, s, &untracked);
|
||||
let common_lifetimes = CommonLifetimes::new(&interners);
|
||||
let common_consts = CommonConsts::new(&interners, &common_types);
|
||||
let common_consts = CommonConsts::new(&interners, &common_types, s, &untracked);
|
||||
|
||||
GlobalCtxt {
|
||||
sess: s,
|
||||
|
@ -1533,7 +1565,6 @@ macro_rules! direct_interners {
|
|||
// crate only, and have a corresponding `mk_` function.
|
||||
direct_interners! {
|
||||
region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>,
|
||||
const_: intern_const(ConstData<'tcx>): Const -> Const<'tcx>,
|
||||
const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
|
||||
layout: pub mk_layout(LayoutS<FieldIdx, VariantIdx>): Layout -> Layout<'tcx>,
|
||||
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
|
||||
|
@ -1710,7 +1741,12 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
|
||||
#[inline]
|
||||
pub fn mk_ct_from_kind(self, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
|
||||
self.intern_const(ty::ConstData { kind, ty })
|
||||
self.interners.intern_const(
|
||||
ty::ConstData { kind, ty },
|
||||
self.sess,
|
||||
// This is only used to create a stable hashing context.
|
||||
&self.untracked,
|
||||
)
|
||||
}
|
||||
|
||||
// Avoid this in favour of more specific `Ty::new_*` methods, where possible.
|
||||
|
|
|
@ -28,10 +28,11 @@ impl FlagComputation {
|
|||
result
|
||||
}
|
||||
|
||||
pub fn for_const(c: ty::Const<'_>) -> TypeFlags {
|
||||
pub fn for_const(c: &ty::ConstKind<'_>, t: Ty<'_>) -> FlagComputation {
|
||||
let mut result = FlagComputation::new();
|
||||
result.add_const(c);
|
||||
result.flags
|
||||
result.add_const_kind(c);
|
||||
result.add_ty(t);
|
||||
result
|
||||
}
|
||||
|
||||
fn add_flags(&mut self, flags: TypeFlags) {
|
||||
|
@ -297,8 +298,12 @@ impl FlagComputation {
|
|||
}
|
||||
|
||||
fn add_const(&mut self, c: ty::Const<'_>) {
|
||||
self.add_ty(c.ty());
|
||||
match c.kind() {
|
||||
self.add_flags(c.flags());
|
||||
self.add_exclusive_binder(c.outer_exclusive_binder());
|
||||
}
|
||||
|
||||
fn add_const_kind(&mut self, c: &ty::ConstKind<'_>) {
|
||||
match *c {
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
self.add_args(uv.args);
|
||||
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
|
||||
|
|
|
@ -70,7 +70,7 @@ impl<'tcx> GenericArgKind<'tcx> {
|
|||
GenericArgKind::Const(ct) => {
|
||||
// Ensure we can use the tag bits.
|
||||
assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
|
||||
(CONST_TAG, ct.0.0 as *const ty::ConstData<'tcx> as usize)
|
||||
(CONST_TAG, ct.0.0 as *const WithCachedTypeInfo<ty::ConstData<'tcx>> as usize)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -136,7 +136,7 @@ impl<'tcx> GenericArg<'tcx> {
|
|||
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
|
||||
))),
|
||||
CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
|
||||
&*((ptr & !TAG_MASK) as *const ty::ConstData<'tcx>),
|
||||
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::ConstData<'tcx>>),
|
||||
))),
|
||||
_ => intrinsics::unreachable(),
|
||||
}
|
||||
|
|
|
@ -900,7 +900,7 @@ impl<'tcx> Term<'tcx> {
|
|||
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::TyKind<'tcx>>),
|
||||
))),
|
||||
CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
|
||||
&*((ptr & !TAG_MASK) as *const ty::ConstData<'tcx>),
|
||||
&*((ptr & !TAG_MASK) as *const WithCachedTypeInfo<ty::ConstData<'tcx>>),
|
||||
))),
|
||||
_ => core::intrinsics::unreachable(),
|
||||
}
|
||||
|
@ -967,7 +967,7 @@ impl<'tcx> TermKind<'tcx> {
|
|||
TermKind::Const(ct) => {
|
||||
// Ensure we can use the tag bits.
|
||||
assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
|
||||
(CONST_TAG, ct.0.0 as *const ty::ConstData<'tcx> as usize)
|
||||
(CONST_TAG, ct.0.0 as *const WithCachedTypeInfo<ty::ConstData<'tcx>> as usize)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
|
||||
use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
|
@ -440,16 +440,15 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasEscapingVarsVisitor {
|
|||
}
|
||||
|
||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
// we don't have a `visit_infer_const` callback, so we have to
|
||||
// hook in here to catch this case (annoying...), but
|
||||
// otherwise we do want to remember to visit the rest of the
|
||||
// const, as it has types/regions embedded in a lot of other
|
||||
// places.
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
|
||||
// If the outer-exclusive-binder is *strictly greater* than
|
||||
// `outer_index`, that means that `ct` contains some content
|
||||
// bound at `outer_index` or above (because
|
||||
// `outer_exclusive_binder` is always 1 higher than the
|
||||
// content in `t`). Therefore, `t` has some escaping vars.
|
||||
if ct.outer_exclusive_binder() > self.outer_index {
|
||||
ControlFlow::Break(FoundEscapingVars)
|
||||
}
|
||||
_ => ct.super_visit_with(self),
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -529,9 +528,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
|
|||
#[inline]
|
||||
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
// Note: no `super_visit_with` call.
|
||||
let flags = FlagComputation::for_const(c);
|
||||
trace!(r.flags=?flags);
|
||||
if flags.intersects(self.flags) {
|
||||
if c.flags().intersects(self.flags) {
|
||||
ControlFlow::Break(FoundFlags)
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
|
|
|
@ -618,6 +618,22 @@ fn replace_resume_ty_local<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Transforms the `body` of the coroutine applying the following transform:
|
||||
///
|
||||
/// - Remove the `resume` argument.
|
||||
///
|
||||
/// Ideally the async lowering would not add the `resume` argument.
|
||||
///
|
||||
/// The async lowering step and the type / lifetime inference / checking are
|
||||
/// still using the `resume` argument for the time being. After this transform,
|
||||
/// the coroutine body doesn't have the `resume` argument.
|
||||
fn transform_gen_context<'tcx>(_tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
// This leaves the local representing the `resume` argument in place,
|
||||
// but turns it into a regular local variable. This is cheaper than
|
||||
// adjusting all local references in the body after removing it.
|
||||
body.arg_count = 1;
|
||||
}
|
||||
|
||||
struct LivenessInfo {
|
||||
/// Which locals are live across any suspension point.
|
||||
saved_locals: CoroutineSavedLocals,
|
||||
|
@ -1338,7 +1354,15 @@ fn create_coroutine_resume_function<'tcx>(
|
|||
insert_switch(body, cases, &transform, TerminatorKind::Unreachable);
|
||||
|
||||
make_coroutine_state_argument_indirect(tcx, body);
|
||||
|
||||
match coroutine_kind {
|
||||
// Iterator::next doesn't accept a pinned argument,
|
||||
// unlike for all other coroutine kinds.
|
||||
CoroutineKind::Gen(_) => {}
|
||||
_ => {
|
||||
make_coroutine_state_argument_pinned(tcx, body);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we remove dead blocks to remove
|
||||
// unrelated code from the drop part of the function
|
||||
|
@ -1505,6 +1529,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
|
|||
};
|
||||
|
||||
let is_async_kind = matches!(body.coroutine_kind(), Some(CoroutineKind::Async(_)));
|
||||
let is_gen_kind = matches!(body.coroutine_kind(), Some(CoroutineKind::Gen(_)));
|
||||
let (state_adt_ref, state_args) = match body.coroutine_kind().unwrap() {
|
||||
CoroutineKind::Async(_) => {
|
||||
// Compute Poll<return_ty>
|
||||
|
@ -1610,6 +1635,11 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
|
|||
body.arg_count = 2; // self, resume arg
|
||||
body.spread_arg = None;
|
||||
|
||||
// Remove the context argument within generator bodies.
|
||||
if is_gen_kind {
|
||||
transform_gen_context(tcx, body);
|
||||
}
|
||||
|
||||
// The original arguments to the function are no longer arguments, mark them as such.
|
||||
// Otherwise they'll conflict with our new arguments, which although they don't have
|
||||
// argument_index set, will get emitted as unnamed arguments.
|
||||
|
|
|
@ -37,7 +37,7 @@ impl BoundModifiers {
|
|||
(BoundPolarity::Positive, None) => TraitBoundModifier::None,
|
||||
(BoundPolarity::Negative(_), None) => TraitBoundModifier::Negative,
|
||||
(BoundPolarity::Maybe(_), None) => TraitBoundModifier::Maybe,
|
||||
(BoundPolarity::Positive, Some(_)) => TraitBoundModifier::MaybeConst,
|
||||
(BoundPolarity::Positive, Some(sp)) => TraitBoundModifier::MaybeConst(sp),
|
||||
(BoundPolarity::Negative(_), Some(_)) => TraitBoundModifier::MaybeConstNegative,
|
||||
(BoundPolarity::Maybe(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ pub struct QueryInfo {
|
|||
pub type QueryMap = FxHashMap<QueryJobId, QueryJobInfo>;
|
||||
|
||||
/// A value uniquely identifying an active query job.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct QueryJobId(pub NonZeroU64);
|
||||
|
||||
impl QueryJobId {
|
||||
|
@ -62,14 +62,14 @@ impl QueryJobId {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct QueryJobInfo {
|
||||
pub query: QueryStackFrame,
|
||||
pub job: QueryJob,
|
||||
}
|
||||
|
||||
/// Represents an active query job.
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct QueryJob {
|
||||
pub id: QueryJobId,
|
||||
|
||||
|
@ -182,6 +182,7 @@ impl QueryJobId {
|
|||
}
|
||||
|
||||
#[cfg(parallel_compiler)]
|
||||
#[derive(Debug)]
|
||||
struct QueryWaiter {
|
||||
query: Option<QueryJobId>,
|
||||
condvar: Condvar,
|
||||
|
@ -198,13 +199,14 @@ impl QueryWaiter {
|
|||
}
|
||||
|
||||
#[cfg(parallel_compiler)]
|
||||
#[derive(Debug)]
|
||||
struct QueryLatchInfo {
|
||||
complete: bool,
|
||||
waiters: Vec<Arc<QueryWaiter>>,
|
||||
}
|
||||
|
||||
#[cfg(parallel_compiler)]
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub(super) struct QueryLatch {
|
||||
info: Arc<Mutex<QueryLatchInfo>>,
|
||||
}
|
||||
|
@ -540,7 +542,11 @@ pub fn deadlock(query_map: QueryMap, registry: &rayon_core::Registry) {
|
|||
// X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here
|
||||
// only considers the true dependency and won't detect a cycle.
|
||||
if !found_cycle {
|
||||
panic!("deadlock detected");
|
||||
if query_map.len() == 0 {
|
||||
panic!("deadlock detected without any query!")
|
||||
} else {
|
||||
panic!("deadlock detected! current query map:\n{:#?}", query_map);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Ensure this won't cause a deadlock before we return
|
||||
|
|
|
@ -203,7 +203,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct CycleError {
|
||||
/// The query and related span that uses the cycle.
|
||||
pub usage: Option<(Span, QueryStackFrame)>,
|
||||
|
|
|
@ -2162,13 +2162,22 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
|||
fn let_binding_suggestion(&mut self, err: &mut Diagnostic, ident_span: Span) -> bool {
|
||||
if let Some(Expr { kind: ExprKind::Assign(lhs, ..), .. }) =
|
||||
self.diagnostic_metadata.in_assignment
|
||||
&& let ast::ExprKind::Path(None, _) = lhs.kind
|
||||
&& let ast::ExprKind::Path(None, ref path) = lhs.kind
|
||||
{
|
||||
if !ident_span.from_expansion() {
|
||||
let (span, text) = match path.segments.first() {
|
||||
Some(seg) if let Some(name) = seg.ident.as_str().strip_prefix("let") => {
|
||||
// a special case for #117894
|
||||
let name = name.strip_prefix("_").unwrap_or(name);
|
||||
(ident_span, format!("let {name}"))
|
||||
}
|
||||
_ => (ident_span.shrink_to_lo(), "let ".to_string()),
|
||||
};
|
||||
|
||||
err.span_suggestion_verbose(
|
||||
ident_span.shrink_to_lo(),
|
||||
span,
|
||||
"you might have meant to introduce a new binding",
|
||||
"let ".to_string(),
|
||||
text,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
return true;
|
||||
|
|
|
@ -11,8 +11,8 @@ use stable_mir::mir::alloc::AllocId;
|
|||
use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
|
||||
use stable_mir::ty::{
|
||||
AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const,
|
||||
ExistentialTraitRef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, TraitRef,
|
||||
Ty, UintTy,
|
||||
ExistentialTraitRef, FloatTy, GenericArgKind, GenericArgs, IntTy, Region, RigidTy, Span,
|
||||
TraitRef, Ty, UintTy,
|
||||
};
|
||||
use stable_mir::{CrateItem, DefId};
|
||||
|
||||
|
@ -279,6 +279,14 @@ impl<'tcx> RustcInternal<'tcx> for AdtDef {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> RustcInternal<'tcx> for Span {
|
||||
type T = rustc_span::Span;
|
||||
|
||||
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||
tables[*self]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> RustcInternal<'tcx> for &T
|
||||
where
|
||||
T: RustcInternal<'tcx>,
|
||||
|
|
|
@ -14,6 +14,7 @@ use rustc_hir::def::DefKind;
|
|||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{alloc_range, AllocId};
|
||||
use rustc_middle::mir::mono::MonoItem;
|
||||
use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
|
||||
use rustc_middle::ty::{self, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, Variance};
|
||||
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc_target::abi::FieldIdx;
|
||||
|
@ -28,7 +29,7 @@ use stable_mir::ty::{
|
|||
EarlyParamRegion, FloatTy, FnDef, GenericArgs, GenericParamDef, IntTy, LineInfo, Movability,
|
||||
RigidTy, Span, TyKind, UintTy,
|
||||
};
|
||||
use stable_mir::{self, opaque, Context, CrateItem, Error, Filename, ItemKind};
|
||||
use stable_mir::{self, opaque, Context, Crate, CrateItem, Error, Filename, ItemKind, Symbol};
|
||||
use std::cell::RefCell;
|
||||
use tracing::debug;
|
||||
|
||||
|
@ -61,9 +62,18 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
crates
|
||||
}
|
||||
|
||||
fn name_of_def_id(&self, def_id: stable_mir::DefId) -> String {
|
||||
fn def_name(&self, def_id: stable_mir::DefId, trimmed: bool) -> Symbol {
|
||||
let tables = self.0.borrow();
|
||||
tables.tcx.def_path_str(tables[def_id])
|
||||
if trimmed {
|
||||
with_forced_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
|
||||
} else {
|
||||
with_no_trimmed_paths!(tables.tcx.def_path_str(tables[def_id]))
|
||||
}
|
||||
}
|
||||
|
||||
fn krate(&self, def_id: stable_mir::DefId) -> Crate {
|
||||
let tables = self.0.borrow();
|
||||
smir_crate(tables.tcx, tables[def_id].krate)
|
||||
}
|
||||
|
||||
fn span_to_string(&self, span: stable_mir::ty::Span) -> String {
|
||||
|
@ -240,10 +250,27 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
|
|||
tables.create_def_id(def_id)
|
||||
}
|
||||
|
||||
fn instance_mangled_name(&self, def: InstanceDef) -> String {
|
||||
fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol {
|
||||
let tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[instance];
|
||||
tables.tcx.symbol_name(instance).name.to_string()
|
||||
}
|
||||
|
||||
/// Retrieve the instance name for diagnostic messages.
|
||||
///
|
||||
/// This will return the specialized name, e.g., `Vec<char>::new`.
|
||||
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol {
|
||||
let tables = self.0.borrow_mut();
|
||||
let instance = tables.instances[def];
|
||||
tables.tcx.symbol_name(instance).name.to_string()
|
||||
if trimmed {
|
||||
with_forced_trimmed_paths!(
|
||||
tables.tcx.def_path_str_with_args(instance.def_id(), instance.args)
|
||||
)
|
||||
} else {
|
||||
with_no_trimmed_paths!(
|
||||
tables.tcx.def_path_str_with_args(instance.def_id(), instance.args)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn mono_instance(&self, item: stable_mir::CrateItem) -> stable_mir::mir::mono::Instance {
|
||||
|
|
|
@ -787,6 +787,7 @@ symbols! {
|
|||
fmt,
|
||||
fmul_fast,
|
||||
fn_align,
|
||||
fn_delegation,
|
||||
fn_must_use,
|
||||
fn_mut,
|
||||
fn_once,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::EvalCtxt;
|
||||
use super::{EvalCtxt, NestedGoals};
|
||||
use crate::solve::inspect;
|
||||
use rustc_middle::traits::query::NoSolution;
|
||||
|
||||
|
@ -14,7 +14,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
predefined_opaques_in_body: self.predefined_opaques_in_body,
|
||||
max_input_universe: self.max_input_universe,
|
||||
search_graph: self.search_graph,
|
||||
nested_goals: self.nested_goals.clone(),
|
||||
nested_goals: NestedGoals::new(),
|
||||
tainted: self.tainted,
|
||||
inspect: self.inspect.new_probe(),
|
||||
};
|
||||
|
@ -32,7 +32,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
tainted,
|
||||
inspect,
|
||||
} = nested_ecx;
|
||||
self.nested_goals = nested_goals;
|
||||
self.nested_goals.extend(nested_goals);
|
||||
self.tainted = tainted;
|
||||
self.inspect.integrate_snapshot(inspect);
|
||||
} else {
|
||||
|
|
|
@ -108,7 +108,7 @@ pub(super) struct NestedGoals<'tcx> {
|
|||
pub(super) goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
|
||||
}
|
||||
|
||||
impl NestedGoals<'_> {
|
||||
impl<'tcx> NestedGoals<'tcx> {
|
||||
pub(super) fn new() -> Self {
|
||||
Self { normalizes_to_hack_goal: None, goals: Vec::new() }
|
||||
}
|
||||
|
@ -116,6 +116,11 @@ impl NestedGoals<'_> {
|
|||
pub(super) fn is_empty(&self) -> bool {
|
||||
self.normalizes_to_hack_goal.is_none() && self.goals.is_empty()
|
||||
}
|
||||
|
||||
pub(super) fn extend(&mut self, other: NestedGoals<'tcx>) {
|
||||
assert_eq!(other.normalizes_to_hack_goal, None);
|
||||
self.goals.extend(other.goals)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Hash, HashStable, Clone, Copy)]
|
||||
|
|
|
@ -334,11 +334,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME(@lcnr): If the normalization of the alias adds an inference constraint which
|
||||
// causes a previously added goal to fail, then we treat the alias as rigid.
|
||||
//
|
||||
// These feels like a potential issue, I should look into writing some tests here
|
||||
// and then probably changing `commit_if_ok` to not inherit the parent goals.
|
||||
match self.commit_if_ok(|this| {
|
||||
let normalized_ty = this.next_ty_infer();
|
||||
let normalizes_to_goal = Goal::new(
|
||||
|
|
|
@ -1050,8 +1050,10 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> {
|
|||
let mut ambiguity_cause = None;
|
||||
for cand in goal.candidates() {
|
||||
// FIXME: boiiii, using string comparisions here sure is scuffed.
|
||||
if let inspect::ProbeKind::MiscCandidate { name: "coherence unknowable", result: _ } =
|
||||
cand.kind()
|
||||
if let inspect::ProbeKind::MiscCandidate {
|
||||
name: "coherence unknowable",
|
||||
result: Ok(_),
|
||||
} = cand.kind()
|
||||
{
|
||||
let lazily_normalize_ty = |ty: Ty<'tcx>| {
|
||||
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx);
|
||||
|
|
|
@ -160,15 +160,13 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxEscapingBoundVarVisitor {
|
|||
}
|
||||
|
||||
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
match ct.kind() {
|
||||
ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
|
||||
self.escaping =
|
||||
self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
|
||||
if ct.outer_exclusive_binder() > self.outer_index {
|
||||
self.escaping = self
|
||||
.escaping
|
||||
.max(ct.outer_exclusive_binder().as_usize() - self.outer_index.as_usize());
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => ct.super_visit_with(self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct QueryNormalizer<'cx, 'tcx> {
|
||||
|
|
|
@ -98,6 +98,7 @@ fn fn_sig_for_fn_abi<'tcx>(
|
|||
)
|
||||
}
|
||||
ty::Coroutine(did, args, _) => {
|
||||
let coroutine_kind = tcx.coroutine_kind(did).unwrap();
|
||||
let sig = args.as_coroutine().poly_sig();
|
||||
|
||||
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
|
||||
|
@ -112,15 +113,29 @@ fn fn_sig_for_fn_abi<'tcx>(
|
|||
let pin_did = tcx.require_lang_item(LangItem::Pin, None);
|
||||
let pin_adt_ref = tcx.adt_def(pin_did);
|
||||
let pin_args = tcx.mk_args(&[env_ty.into()]);
|
||||
let env_ty = Ty::new_adt(tcx, pin_adt_ref, pin_args);
|
||||
let env_ty = match coroutine_kind {
|
||||
hir::CoroutineKind::Gen(_) => {
|
||||
// Iterator::next doesn't accept a pinned argument,
|
||||
// unlike for all other coroutine kinds.
|
||||
env_ty
|
||||
}
|
||||
hir::CoroutineKind::Async(_) | hir::CoroutineKind::Coroutine => {
|
||||
Ty::new_adt(tcx, pin_adt_ref, pin_args)
|
||||
}
|
||||
};
|
||||
|
||||
let sig = sig.skip_binder();
|
||||
// The `FnSig` and the `ret_ty` here is for a coroutines main
|
||||
// `Coroutine::resume(...) -> CoroutineState` function in case we
|
||||
// have an ordinary coroutine, or the `Future::poll(...) -> Poll`
|
||||
// function in case this is a special coroutine backing an async construct.
|
||||
let (resume_ty, ret_ty) = if tcx.coroutine_is_async(did) {
|
||||
// have an ordinary coroutine, the `Future::poll(...) -> Poll`
|
||||
// function in case this is a special coroutine backing an async construct
|
||||
// or the `Iterator::next(...) -> Option` function in case this is a
|
||||
// special coroutine backing a gen construct.
|
||||
let (resume_ty, ret_ty) = match coroutine_kind {
|
||||
hir::CoroutineKind::Async(_) => {
|
||||
// The signature should be `Future::poll(_, &mut Context<'_>) -> Poll<Output>`
|
||||
assert_eq!(sig.yield_ty, tcx.types.unit);
|
||||
|
||||
let poll_did = tcx.require_lang_item(LangItem::Poll, None);
|
||||
let poll_adt_ref = tcx.adt_def(poll_did);
|
||||
let poll_args = tcx.mk_args(&[sig.return_ty.into()]);
|
||||
|
@ -140,27 +155,50 @@ fn fn_sig_for_fn_abi<'tcx>(
|
|||
}
|
||||
let context_mut_ref = Ty::new_task_context(tcx);
|
||||
|
||||
(context_mut_ref, ret_ty)
|
||||
} else {
|
||||
(Some(context_mut_ref), ret_ty)
|
||||
}
|
||||
hir::CoroutineKind::Gen(_) => {
|
||||
// The signature should be `Iterator::next(_) -> Option<Yield>`
|
||||
let option_did = tcx.require_lang_item(LangItem::Option, None);
|
||||
let option_adt_ref = tcx.adt_def(option_did);
|
||||
let option_args = tcx.mk_args(&[sig.yield_ty.into()]);
|
||||
let ret_ty = Ty::new_adt(tcx, option_adt_ref, option_args);
|
||||
|
||||
assert_eq!(sig.return_ty, tcx.types.unit);
|
||||
assert_eq!(sig.resume_ty, tcx.types.unit);
|
||||
|
||||
(None, ret_ty)
|
||||
}
|
||||
hir::CoroutineKind::Coroutine => {
|
||||
// The signature should be `Coroutine::resume(_, Resume) -> CoroutineState<Yield, Return>`
|
||||
let state_did = tcx.require_lang_item(LangItem::CoroutineState, None);
|
||||
let state_adt_ref = tcx.adt_def(state_did);
|
||||
let state_args = tcx.mk_args(&[sig.yield_ty.into(), sig.return_ty.into()]);
|
||||
let ret_ty = Ty::new_adt(tcx, state_adt_ref, state_args);
|
||||
|
||||
(sig.resume_ty, ret_ty)
|
||||
(Some(sig.resume_ty), ret_ty)
|
||||
}
|
||||
};
|
||||
|
||||
ty::Binder::bind_with_vars(
|
||||
let fn_sig = if let Some(resume_ty) = resume_ty {
|
||||
tcx.mk_fn_sig(
|
||||
[env_ty, resume_ty],
|
||||
ret_ty,
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
rustc_target::spec::abi::Abi::Rust,
|
||||
),
|
||||
bound_vars,
|
||||
)
|
||||
} else {
|
||||
// `Iterator::next` doesn't have a `resume` argument.
|
||||
tcx.mk_fn_sig(
|
||||
[env_ty],
|
||||
ret_ty,
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
rustc_target::spec::abi::Abi::Rust,
|
||||
)
|
||||
};
|
||||
ty::Binder::bind_with_vars(fn_sig, bound_vars)
|
||||
}
|
||||
_ => bug!("unexpected type {:?} in Instance::fn_sig", ty),
|
||||
}
|
||||
|
|
69
compiler/stable_mir/src/crate_def.rs
Normal file
69
compiler/stable_mir/src/crate_def.rs
Normal file
|
@ -0,0 +1,69 @@
|
|||
//! Module that define a common trait for things that represent a crate definition,
|
||||
//! such as, a function, a trait, an enum, and any other definitions.
|
||||
|
||||
use crate::ty::Span;
|
||||
use crate::{with, Crate, Symbol};
|
||||
|
||||
/// A unique identification number for each item accessible for the current compilation unit.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct DefId(pub(crate) usize);
|
||||
|
||||
/// A trait for retrieving information about a particular definition.
|
||||
///
|
||||
/// Implementors must provide the implementation of `def_id` which will be used to retrieve
|
||||
/// information about a crate's definition.
|
||||
pub trait CrateDef {
|
||||
/// Retrieve the unique identifier for the current definition.
|
||||
fn def_id(&self) -> DefId;
|
||||
|
||||
/// Return the fully qualified name of the current definition.
|
||||
fn name(&self) -> Symbol {
|
||||
let def_id = self.def_id();
|
||||
with(|cx| cx.def_name(def_id, false))
|
||||
}
|
||||
|
||||
/// Return a trimmed name of this definition.
|
||||
///
|
||||
/// This can be used to print more user friendly diagnostic messages.
|
||||
///
|
||||
/// If a symbol name can only be imported from one place for a type, and as
|
||||
/// long as it was not glob-imported anywhere in the current crate, we trim its
|
||||
/// path and print only the name.
|
||||
///
|
||||
/// For example, this function may shorten `std::vec::Vec` to just `Vec`,
|
||||
/// as long as there is no other `Vec` importable anywhere.
|
||||
fn trimmed_name(&self) -> Symbol {
|
||||
let def_id = self.def_id();
|
||||
with(|cx| cx.def_name(def_id, true))
|
||||
}
|
||||
|
||||
/// Return information about the crate where this definition is declared.
|
||||
///
|
||||
/// This will return the crate number and its name.
|
||||
fn krate(&self) -> Crate {
|
||||
let def_id = self.def_id();
|
||||
with(|cx| cx.krate(def_id))
|
||||
}
|
||||
|
||||
/// Return the span of this definition.
|
||||
fn span(&self) -> Span {
|
||||
let def_id = self.def_id();
|
||||
with(|cx| cx.span_of_an_item(def_id))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! crate_def {
|
||||
( $(#[$attr:meta])*
|
||||
$vis:vis $name:ident $(;)?
|
||||
) => {
|
||||
$(#[$attr])*
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
$vis struct $name(pub DefId);
|
||||
|
||||
impl CrateDef for $name {
|
||||
fn def_id(&self) -> DefId {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -31,12 +31,16 @@ use self::ty::{
|
|||
#[macro_use]
|
||||
extern crate scoped_tls;
|
||||
|
||||
#[macro_use]
|
||||
pub mod crate_def;
|
||||
#[macro_use]
|
||||
pub mod error;
|
||||
pub mod mir;
|
||||
pub mod ty;
|
||||
pub mod visitor;
|
||||
|
||||
pub use crate::crate_def::CrateDef;
|
||||
pub use crate::crate_def::DefId;
|
||||
use crate::mir::alloc::{AllocId, GlobalAlloc};
|
||||
use crate::mir::pretty::function_name;
|
||||
use crate::mir::Mutability;
|
||||
|
@ -51,15 +55,11 @@ pub type Symbol = String;
|
|||
/// The number that identifies a crate.
|
||||
pub type CrateNum = usize;
|
||||
|
||||
/// A unique identification number for each item accessible for the current compilation unit.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct DefId(usize);
|
||||
|
||||
impl Debug for DefId {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("DefId")
|
||||
.field("id", &self.0)
|
||||
.field("name", &with(|cx| cx.name_of_def_id(*self)))
|
||||
.field("name", &with(|cx| cx.def_name(*self, false)))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -100,9 +100,10 @@ pub enum ItemKind {
|
|||
|
||||
pub type Filename = String;
|
||||
|
||||
/// Holds information about an item in the crate.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct CrateItem(pub DefId);
|
||||
crate_def! {
|
||||
/// Holds information about an item in a crate.
|
||||
pub CrateItem;
|
||||
}
|
||||
|
||||
impl CrateItem {
|
||||
pub fn body(&self) -> mir::Body {
|
||||
|
@ -113,10 +114,6 @@ impl CrateItem {
|
|||
with(|cx| cx.span_of_an_item(self.0))
|
||||
}
|
||||
|
||||
pub fn name(&self) -> String {
|
||||
with(|cx| cx.name_of_def_id(self.0))
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> ItemKind {
|
||||
with(|cx| cx.item_kind(*self))
|
||||
}
|
||||
|
@ -205,7 +202,7 @@ pub trait Context {
|
|||
fn find_crates(&self, name: &str) -> Vec<Crate>;
|
||||
|
||||
/// Returns the name of given `DefId`
|
||||
fn name_of_def_id(&self, def_id: DefId) -> String;
|
||||
fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol;
|
||||
|
||||
/// Returns printable, human readable form of `Span`
|
||||
fn span_to_string(&self, span: Span) -> String;
|
||||
|
@ -260,7 +257,7 @@ pub trait Context {
|
|||
fn instance_def_id(&self, instance: InstanceDef) -> DefId;
|
||||
|
||||
/// Get the instance mangled name.
|
||||
fn instance_mangled_name(&self, instance: InstanceDef) -> String;
|
||||
fn instance_mangled_name(&self, instance: InstanceDef) -> Symbol;
|
||||
|
||||
/// Convert a non-generic crate item into an instance.
|
||||
/// This function will panic if the item is generic.
|
||||
|
@ -294,6 +291,8 @@ pub trait Context {
|
|||
|
||||
/// Retrieve the id for the virtual table.
|
||||
fn vtable_allocation(&self, global_alloc: &GlobalAlloc) -> Option<AllocId>;
|
||||
fn krate(&self, def_id: DefId) -> Crate;
|
||||
fn instance_name(&self, def: InstanceDef, trimmed: bool) -> Symbol;
|
||||
}
|
||||
|
||||
// A thread local variable that stores a pointer to the tables mapping between TyCtxt
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::crate_def::CrateDef;
|
||||
use crate::mir::Body;
|
||||
use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
|
||||
use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque};
|
||||
use crate::{with, CrateItem, DefId, Error, ItemKind, Opaque, Symbol};
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
@ -47,10 +48,29 @@ impl Instance {
|
|||
with(|context| context.instance_ty(self.def))
|
||||
}
|
||||
|
||||
pub fn mangled_name(&self) -> String {
|
||||
/// Retrieve the instance's mangled name used for calling the given instance.
|
||||
///
|
||||
/// This will also look up the correct name of instances from upstream crates.
|
||||
pub fn mangled_name(&self) -> Symbol {
|
||||
with(|context| context.instance_mangled_name(self.def))
|
||||
}
|
||||
|
||||
/// Retrieve the instance name for diagnostic messages.
|
||||
///
|
||||
/// This will return the specialized name, e.g., `std::vec::Vec<u8>::new`.
|
||||
pub fn name(&self) -> Symbol {
|
||||
with(|context| context.instance_name(self.def, false))
|
||||
}
|
||||
|
||||
/// Return a trimmed name of the given instance including its args.
|
||||
///
|
||||
/// If a symbol name can only be imported from one place for a type, and as
|
||||
/// long as it was not glob-imported anywhere in the current crate, we trim its
|
||||
/// path and print only the name.
|
||||
pub fn trimmed_name(&self) -> Symbol {
|
||||
with(|context| context.instance_name(self.def, true))
|
||||
}
|
||||
|
||||
/// Resolve an instance starting from a function definition and generic arguments.
|
||||
pub fn resolve(def: FnDef, args: &GenericArgs) -> Result<Instance, crate::Error> {
|
||||
with(|context| {
|
||||
|
@ -104,6 +124,8 @@ impl TryFrom<CrateItem> for Instance {
|
|||
|
||||
fn try_from(item: CrateItem) -> Result<Self, Self::Error> {
|
||||
with(|context| {
|
||||
// FIXME(celinval):
|
||||
// - Return `Err` if instance does not have a body.
|
||||
if !context.requires_monomorphization(item.0) {
|
||||
Ok(context.mono_instance(item))
|
||||
} else {
|
||||
|
@ -148,8 +170,10 @@ impl From<StaticDef> for CrateItem {
|
|||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct InstanceDef(usize);
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub struct StaticDef(pub DefId);
|
||||
crate_def! {
|
||||
/// Holds information about a static variable definition.
|
||||
pub StaticDef;
|
||||
}
|
||||
|
||||
impl TryFrom<CrateItem> for StaticDef {
|
||||
type Error = crate::Error;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::crate_def::CrateDef;
|
||||
use crate::mir::{Operand, Rvalue, StatementKind};
|
||||
use crate::ty::{DynKind, FloatTy, IntTy, RigidTy, TyKind, UintTy};
|
||||
use crate::{with, Body, CrateItem, Mutability};
|
||||
|
|
|
@ -3,6 +3,7 @@ use super::{
|
|||
mir::{Body, Mutability},
|
||||
with, DefId, Error, Symbol,
|
||||
};
|
||||
use crate::crate_def::CrateDef;
|
||||
use crate::mir::alloc::AllocId;
|
||||
use crate::{Filename, Opaque};
|
||||
use std::fmt::{self, Debug, Display, Formatter};
|
||||
|
@ -295,11 +296,15 @@ pub enum Movability {
|
|||
Movable,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct ForeignDef(pub DefId);
|
||||
crate_def! {
|
||||
/// Hold information about a ForeignItem in a crate.
|
||||
pub ForeignDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct FnDef(pub DefId);
|
||||
crate_def! {
|
||||
/// Hold information about a function definition in a crate.
|
||||
pub FnDef;
|
||||
}
|
||||
|
||||
impl FnDef {
|
||||
pub fn body(&self) -> Body {
|
||||
|
@ -307,20 +312,25 @@ impl FnDef {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct ClosureDef(pub DefId);
|
||||
crate_def! {
|
||||
pub ClosureDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct CoroutineDef(pub DefId);
|
||||
crate_def! {
|
||||
pub CoroutineDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct ParamDef(pub DefId);
|
||||
crate_def! {
|
||||
pub ParamDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct BrNamedDef(pub DefId);
|
||||
crate_def! {
|
||||
pub BrNamedDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct AdtDef(pub DefId);
|
||||
crate_def! {
|
||||
pub AdtDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
||||
pub enum AdtKind {
|
||||
|
@ -363,26 +373,33 @@ impl AdtKind {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct AliasDef(pub DefId);
|
||||
crate_def! {
|
||||
pub AliasDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct TraitDef(pub DefId);
|
||||
crate_def! {
|
||||
pub TraitDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct GenericDef(pub DefId);
|
||||
crate_def! {
|
||||
pub GenericDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct ConstDef(pub DefId);
|
||||
crate_def! {
|
||||
pub ConstDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct ImplDef(pub DefId);
|
||||
crate_def! {
|
||||
pub ImplDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct RegionDef(pub DefId);
|
||||
crate_def! {
|
||||
pub RegionDef;
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct CoroutineWitnessDef(pub DefId);
|
||||
crate_def! {
|
||||
pub CoroutineWitnessDef;
|
||||
}
|
||||
|
||||
/// A list of generic arguments.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
|
|
|
@ -450,7 +450,11 @@ impl Layout {
|
|||
return Err(LayoutError);
|
||||
}
|
||||
|
||||
let array_size = element_size * n;
|
||||
// SAFETY: We just checked that we won't overflow `usize` when we multiply.
|
||||
// This is a useless hint inside this function, but after inlining this helps
|
||||
// deduplicate checks for whether the overall capacity is zero (e.g., in RawVec's
|
||||
// allocation path) before/after this multiplication.
|
||||
let array_size = unsafe { element_size.unchecked_mul(n) };
|
||||
|
||||
// SAFETY: We just checked above that the `array_size` will not
|
||||
// exceed `isize::MAX` even when rounded up to the alignment.
|
||||
|
|
|
@ -115,6 +115,11 @@ use crate::intrinsics;
|
|||
pub trait Any: 'static {
|
||||
/// Gets the `TypeId` of `self`.
|
||||
///
|
||||
/// If called on a `dyn Any` trait object
|
||||
/// (or a trait object of a subtrait of `Any`),
|
||||
/// this returns the `TypeId` of the underlying
|
||||
/// concrete type, not that of `dyn Any` itself.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
|
@ -409,8 +409,7 @@ impl<T> Cell<T> {
|
|||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn set(&self, val: T) {
|
||||
let old = self.replace(val);
|
||||
drop(old);
|
||||
self.replace(val);
|
||||
}
|
||||
|
||||
/// Swaps the values of two `Cell`s.
|
||||
|
|
|
@ -193,7 +193,7 @@
|
|||
//! 27 | | )
|
||||
//! | |_____- binding declared here but left uninitialized
|
||||
//!
|
||||
//! error: aborting due to previous error
|
||||
//! error: aborting due to 1 previous error
|
||||
//!
|
||||
//! For more information about this error, try `rustc --explain E0381`.
|
||||
//! ```
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
//! the `n` parameter is 0, the function is assumed to not be UB. Furthermore, for `memcpy`, if
|
||||
//! source and target pointer are equal, the function is assumed to not be UB.
|
||||
//! (Note that these are standard assumptions among compilers:
|
||||
//! [clang](https://reviews.llvm.org/D86993) and [GCC](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=32667) do the same.)
|
||||
//! [clang](https://reviews.llvm.org/D86993) and [GCC](https://gcc.gnu.org/onlinedocs/gcc/Standards.html#C-Language) do the same.)
|
||||
//! These functions are often provided by the system libc, but can also be provided by the
|
||||
//! [compiler-builtins crate](https://crates.io/crates/compiler_builtins).
|
||||
//! Note that the library does not guarantee that it will always make these assumptions, so Rust
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use crate::cmp::Ordering::{self, Greater, Less};
|
||||
use crate::cmp::Ordering::{self, Equal, Greater, Less};
|
||||
use crate::fmt;
|
||||
use crate::intrinsics::{assert_unsafe_precondition, exact_div};
|
||||
use crate::marker::Copy;
|
||||
|
@ -2854,14 +2854,13 @@ impl<T> [T] {
|
|||
// we have `left + size/2 < self.len()`, and this is in-bounds.
|
||||
let cmp = f(unsafe { self.get_unchecked(mid) });
|
||||
|
||||
// The reason why we use if/else control flow rather than match
|
||||
// is because match reorders comparison operations, which is perf sensitive.
|
||||
// This is x86 asm for u8: https://rust.godbolt.org/z/8Y8Pra.
|
||||
if cmp == Less {
|
||||
left = mid + 1;
|
||||
} else if cmp == Greater {
|
||||
right = mid;
|
||||
} else {
|
||||
// This control flow produces conditional moves, which results in
|
||||
// fewer branches and instructions than if/else or matching on
|
||||
// cmp::Ordering.
|
||||
// This is x86 asm for u8: https://rust.godbolt.org/z/698eYffTx.
|
||||
left = if cmp == Less { mid + 1 } else { left };
|
||||
right = if cmp == Greater { mid } else { right };
|
||||
if cmp == Equal {
|
||||
// SAFETY: same as the `get_unchecked` above
|
||||
unsafe { crate::intrinsics::assume(mid < self.len()) };
|
||||
return Ok(mid);
|
||||
|
|
|
@ -556,6 +556,10 @@ where
|
|||
/// therefore, using something that implements [`BufRead`], such as
|
||||
/// [`BufReader`], will be more efficient.
|
||||
///
|
||||
/// Repeated calls to the reader use the same cursor, so for example
|
||||
/// calling `read_to_end` twice on a [`File`] will only return the file's
|
||||
/// contents once. It's recommended to first call `rewind()` in that case.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// [`File`]s implement `Read`:
|
||||
|
@ -2044,6 +2048,28 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) -> R
|
|||
}
|
||||
}
|
||||
|
||||
fn skip_until<R: BufRead + ?Sized>(r: &mut R, delim: u8) -> Result<usize> {
|
||||
let mut read = 0;
|
||||
loop {
|
||||
let (done, used) = {
|
||||
let available = match r.fill_buf() {
|
||||
Ok(n) => n,
|
||||
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
match memchr::memchr(delim, available) {
|
||||
Some(i) => (true, i + 1),
|
||||
None => (false, available.len()),
|
||||
}
|
||||
};
|
||||
r.consume(used);
|
||||
read += used;
|
||||
if done || used == 0 {
|
||||
return Ok(read);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it
|
||||
/// to perform extra ways of reading.
|
||||
///
|
||||
|
@ -2247,6 +2273,68 @@ pub trait BufRead: Read {
|
|||
read_until(self, byte, buf)
|
||||
}
|
||||
|
||||
/// Skip all bytes until the delimiter `byte` or EOF is reached.
|
||||
///
|
||||
/// This function will read (and discard) bytes from the underlying stream until the
|
||||
/// delimiter or EOF is found.
|
||||
///
|
||||
/// If successful, this function will return the total number of bytes read,
|
||||
/// including the delimiter byte.
|
||||
///
|
||||
/// This is useful for efficiently skipping data such as NUL-terminated strings
|
||||
/// in binary file formats without buffering.
|
||||
///
|
||||
/// This function is blocking and should be used carefully: it is possible for
|
||||
/// an attacker to continuously send bytes without ever sending the delimiter
|
||||
/// or EOF.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will ignore all instances of [`ErrorKind::Interrupted`] and
|
||||
/// will otherwise return any errors returned by [`fill_buf`].
|
||||
///
|
||||
/// If an I/O error is encountered then all bytes read so far will be
|
||||
/// present in `buf` and its length will have been adjusted appropriately.
|
||||
///
|
||||
/// [`fill_buf`]: BufRead::fill_buf
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
|
||||
/// this example, we use [`Cursor`] to read some NUL-terminated information
|
||||
/// about Ferris from a binary string, skipping the fun fact:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(bufread_skip_until)]
|
||||
///
|
||||
/// use std::io::{self, BufRead};
|
||||
///
|
||||
/// let mut cursor = io::Cursor::new(b"Ferris\0Likes long walks on the beach\0Crustacean\0");
|
||||
///
|
||||
/// // read name
|
||||
/// let mut name = Vec::new();
|
||||
/// let num_bytes = cursor.read_until(b'\0', &mut name)
|
||||
/// .expect("reading from cursor won't fail");
|
||||
/// assert_eq!(num_bytes, 7);
|
||||
/// assert_eq!(name, b"Ferris\0");
|
||||
///
|
||||
/// // skip fun fact
|
||||
/// let num_bytes = cursor.skip_until(b'\0')
|
||||
/// .expect("reading from cursor won't fail");
|
||||
/// assert_eq!(num_bytes, 30);
|
||||
///
|
||||
/// // read animal type
|
||||
/// let mut animal = Vec::new();
|
||||
/// let num_bytes = cursor.read_until(b'\0', &mut animal)
|
||||
/// .expect("reading from cursor won't fail");
|
||||
/// assert_eq!(num_bytes, 11);
|
||||
/// assert_eq!(animal, b"Crustacean\0");
|
||||
/// ```
|
||||
#[unstable(feature = "bufread_skip_until", issue = "111735")]
|
||||
fn skip_until(&mut self, byte: u8) -> Result<usize> {
|
||||
skip_until(self, byte)
|
||||
}
|
||||
|
||||
/// Read all bytes until a newline (the `0xA` byte) is reached, and append
|
||||
/// them to the provided `String` buffer.
|
||||
///
|
||||
|
|
|
@ -25,6 +25,36 @@ fn read_until() {
|
|||
assert_eq!(v, []);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn skip_until() {
|
||||
let bytes: &[u8] = b"read\0ignore\0read\0ignore\0read\0ignore\0";
|
||||
let mut reader = BufReader::new(bytes);
|
||||
|
||||
// read from the bytes, alternating between
|
||||
// consuming `read\0`s and skipping `ignore\0`s
|
||||
loop {
|
||||
// consume `read\0`
|
||||
let mut out = Vec::new();
|
||||
let read = reader.read_until(0, &mut out).unwrap();
|
||||
if read == 0 {
|
||||
// eof
|
||||
break;
|
||||
} else {
|
||||
assert_eq!(out, b"read\0");
|
||||
assert_eq!(read, b"read\0".len());
|
||||
}
|
||||
|
||||
// skip past `ignore\0`
|
||||
let skipped = reader.skip_until(0).unwrap();
|
||||
assert_eq!(skipped, b"ignore\0".len());
|
||||
}
|
||||
|
||||
// ensure we are at the end of the byte slice and that we can skip no further
|
||||
// also ensure skip_until matches the behavior of read_until at EOF
|
||||
let skipped = reader.skip_until(0).unwrap();
|
||||
assert_eq!(skipped, 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split() {
|
||||
let buf = Cursor::new(&b"12"[..]);
|
||||
|
|
|
@ -1,8 +1,55 @@
|
|||
//! SOLID-specific extensions to general I/O primitives
|
||||
//!
|
||||
//! Just like raw pointers, raw SOLID Sockets file descriptors point to
|
||||
//! resources with dynamic lifetimes, and they can dangle if they outlive their
|
||||
//! resources or be forged if they're created from invalid values.
|
||||
//!
|
||||
//! This module provides three types for representing raw file descriptors
|
||||
//! with different ownership properties: raw, borrowed, and owned, which are
|
||||
//! analogous to types used for representing pointers:
|
||||
//!
|
||||
//! | Type | Analogous to |
|
||||
//! | ------------------ | ------------ |
|
||||
//! | [`RawFd`] | `*const _` |
|
||||
//! | [`BorrowedFd<'a>`] | `&'a _` |
|
||||
//! | [`OwnedFd`] | `Box<_>` |
|
||||
//!
|
||||
//! Like raw pointers, `RawFd` values are primitive values. And in new code,
|
||||
//! they should be considered unsafe to do I/O on (analogous to dereferencing
|
||||
//! them). Rust did not always provide this guidance, so existing code in the
|
||||
//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Once the
|
||||
//! `io_safety` feature is stable, libraries will be encouraged to migrate,
|
||||
//! either by adding `unsafe` to APIs that dereference `RawFd` values, or by
|
||||
//! using to `BorrowedFd` or `OwnedFd` instead.
|
||||
//!
|
||||
//! Like references, `BorrowedFd` values are tied to a lifetime, to ensure
|
||||
//! that they don't outlive the resource they point to. These are safe to
|
||||
//! use. `BorrowedFd` values may be used in APIs which provide safe access to
|
||||
//! any system call except for:
|
||||
//!
|
||||
//! - `close`, because that would end the dynamic lifetime of the resource
|
||||
//! without ending the lifetime of the file descriptor.
|
||||
//!
|
||||
//! - `dup2`/`dup3`, in the second argument, because this argument is
|
||||
//! closed and assigned a new resource, which may break the assumptions
|
||||
//! other code using that file descriptor.
|
||||
//!
|
||||
//! `BorrowedFd` values may be used in APIs which provide safe access to `dup`
|
||||
//! system calls, so types implementing `AsFd` or `From<OwnedFd>` should not
|
||||
//! assume they always have exclusive access to the underlying file
|
||||
//! description.
|
||||
//!
|
||||
//! Like boxes, `OwnedFd` values conceptually own the resource they point to,
|
||||
//! and free (close) it when they are dropped.
|
||||
//!
|
||||
//! [`BorrowedFd<'a>`]: crate::os::solid::io::BorrowedFd
|
||||
|
||||
#![deny(unsafe_op_in_unsafe_fn)]
|
||||
#![unstable(feature = "solid_ext", issue = "none")]
|
||||
|
||||
use crate::fmt;
|
||||
use crate::marker::PhantomData;
|
||||
use crate::mem::forget;
|
||||
use crate::net;
|
||||
use crate::sys;
|
||||
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
|
||||
|
@ -10,6 +57,253 @@ use crate::sys_common::{self, AsInner, FromInner, IntoInner};
|
|||
/// Raw file descriptors.
|
||||
pub type RawFd = i32;
|
||||
|
||||
/// A borrowed SOLID Sockets file descriptor.
|
||||
///
|
||||
/// This has a lifetime parameter to tie it to the lifetime of something that
|
||||
/// owns the socket.
|
||||
///
|
||||
/// This uses `repr(transparent)` and has the representation of a host file
|
||||
/// descriptor, so it can be used in FFI in places where a socket is passed as
|
||||
/// an argument, it is not captured or consumed, and it never has the value
|
||||
/// `SOLID_NET_INVALID_FD`.
|
||||
///
|
||||
/// This type's `.to_owned()` implementation returns another `BorrowedFd`
|
||||
/// rather than an `OwnedFd`. It just makes a trivial copy of the raw
|
||||
/// socket, which is then borrowed under the same lifetime.
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
#[rustc_layout_scalar_valid_range_start(0)]
|
||||
// This is -2, in two's complement. -1 is `SOLID_NET_INVALID_FD`.
|
||||
#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
|
||||
#[rustc_nonnull_optimization_guaranteed]
|
||||
pub struct BorrowedFd<'socket> {
|
||||
fd: RawFd,
|
||||
_phantom: PhantomData<&'socket OwnedFd>,
|
||||
}
|
||||
|
||||
/// An owned SOLID Sockets file descriptor.
|
||||
///
|
||||
/// This closes the file descriptor on drop.
|
||||
///
|
||||
/// This uses `repr(transparent)` and has the representation of a host file
|
||||
/// descriptor, so it can be used in FFI in places where a socket is passed as
|
||||
/// an argument, it is not captured or consumed, and it never has the value
|
||||
/// `SOLID_NET_INVALID_FD`.
|
||||
#[repr(transparent)]
|
||||
#[rustc_layout_scalar_valid_range_start(0)]
|
||||
// This is -2, in two's complement. -1 is `SOLID_NET_INVALID_FD`.
|
||||
#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
|
||||
#[rustc_nonnull_optimization_guaranteed]
|
||||
pub struct OwnedFd {
|
||||
fd: RawFd,
|
||||
}
|
||||
|
||||
impl BorrowedFd<'_> {
|
||||
/// Return a `BorrowedFd` holding the given raw file descriptor.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The resource pointed to by `fd` must remain open for the duration of
|
||||
/// the returned `BorrowedFd`, and it must not have the value
|
||||
/// `SOLID_NET_INVALID_FD`.
|
||||
#[inline]
|
||||
pub const unsafe fn borrow_raw(fd: RawFd) -> Self {
|
||||
assert!(fd != -1 as RawFd);
|
||||
// SAFETY: we just asserted that the value is in the valid range and
|
||||
// isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
|
||||
unsafe { Self { fd, _phantom: PhantomData } }
|
||||
}
|
||||
}
|
||||
|
||||
impl OwnedFd {
|
||||
/// Creates a new `OwnedFd` instance that shares the same underlying file
|
||||
/// description as the existing `OwnedFd` instance.
|
||||
pub fn try_clone(&self) -> crate::io::Result<Self> {
|
||||
self.as_fd().try_clone_to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl BorrowedFd<'_> {
|
||||
/// Creates a new `OwnedFd` instance that shares the same underlying file
|
||||
/// description as the existing `BorrowedFd` instance.
|
||||
pub fn try_clone_to_owned(&self) -> crate::io::Result<OwnedFd> {
|
||||
let fd = sys::net::cvt(unsafe { sys::net::netc::dup(self.as_raw_fd()) })?;
|
||||
Ok(unsafe { OwnedFd::from_raw_fd(fd) })
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for BorrowedFd<'_> {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for OwnedFd {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for OwnedFd {
|
||||
#[inline]
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
let fd = self.fd;
|
||||
forget(self);
|
||||
fd
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for OwnedFd {
|
||||
/// Constructs a new instance of `Self` from the given raw file descriptor.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The resource pointed to by `fd` must be open and suitable for assuming
|
||||
/// ownership. The resource must not require any cleanup other than `close`.
|
||||
#[inline]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> Self {
|
||||
assert_ne!(fd, -1 as RawFd);
|
||||
// SAFETY: we just asserted that the value is in the valid range and
|
||||
// isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
|
||||
unsafe { Self { fd } }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for OwnedFd {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe { sys::net::netc::close(self.fd) };
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for BorrowedFd<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("BorrowedFd").field("fd", &self.fd).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for OwnedFd {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("OwnedFd").field("fd", &self.fd).finish()
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_is_terminal {
|
||||
($($t:ty),*$(,)?) => {$(
|
||||
#[unstable(feature = "sealed", issue = "none")]
|
||||
impl crate::sealed::Sealed for $t {}
|
||||
|
||||
#[stable(feature = "is_terminal", since = "1.70.0")]
|
||||
impl crate::io::IsTerminal for $t {
|
||||
#[inline]
|
||||
fn is_terminal(&self) -> bool {
|
||||
crate::sys::io::is_terminal(self)
|
||||
}
|
||||
}
|
||||
)*}
|
||||
}
|
||||
|
||||
impl_is_terminal!(BorrowedFd<'_>, OwnedFd);
|
||||
|
||||
/// A trait to borrow the SOLID Sockets file descriptor from an underlying
|
||||
/// object.
|
||||
pub trait AsFd {
|
||||
/// Borrows the file descriptor.
|
||||
fn as_fd(&self) -> BorrowedFd<'_>;
|
||||
}
|
||||
|
||||
impl<T: AsFd> AsFd for &T {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
T::as_fd(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsFd> AsFd for &mut T {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
T::as_fd(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for BorrowedFd<'_> {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl AsFd for OwnedFd {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
// Safety: `OwnedFd` and `BorrowedFd` have the same validity
|
||||
// invariants, and the `BorrowedFd` is bounded by the lifetime
|
||||
// of `&self`.
|
||||
unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_owned_fd_traits {
|
||||
($($t:ident)*) => {$(
|
||||
impl AsFd for net::$t {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.as_inner().socket().as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<net::$t> for OwnedFd {
|
||||
#[inline]
|
||||
fn from(socket: net::$t) -> OwnedFd {
|
||||
socket.into_inner().into_socket().into_inner()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OwnedFd> for net::$t {
|
||||
#[inline]
|
||||
fn from(owned_fd: OwnedFd) -> Self {
|
||||
Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
|
||||
}
|
||||
}
|
||||
)*};
|
||||
}
|
||||
impl_owned_fd_traits! { TcpStream TcpListener UdpSocket }
|
||||
|
||||
/// This impl allows implementing traits that require `AsFd` on Arc.
|
||||
/// ```
|
||||
/// # #[cfg(target_os = "solid_asp3")] mod group_cfg {
|
||||
/// # use std::os::solid::io::AsFd;
|
||||
/// use std::net::UdpSocket;
|
||||
/// use std::sync::Arc;
|
||||
///
|
||||
/// trait MyTrait: AsFd {}
|
||||
/// impl MyTrait for Arc<UdpSocket> {}
|
||||
/// impl MyTrait for Box<UdpSocket> {}
|
||||
/// # }
|
||||
/// ```
|
||||
impl<T: AsFd> AsFd for crate::sync::Arc<T> {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
(**self).as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsFd> AsFd for crate::rc::Rc<T> {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
(**self).as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsFd> AsFd for Box<T> {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
(**self).as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait to extract the raw SOLID Sockets file descriptor from an underlying
|
||||
/// object.
|
||||
pub trait AsRawFd {
|
||||
|
@ -84,7 +378,7 @@ macro_rules! impl_as_raw_fd {
|
|||
impl AsRawFd for net::$t {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
*self.as_inner().socket().as_inner()
|
||||
self.as_inner().socket().as_raw_fd()
|
||||
}
|
||||
}
|
||||
)*};
|
||||
|
@ -97,7 +391,7 @@ macro_rules! impl_from_raw_fd {
|
|||
impl FromRawFd for net::$t {
|
||||
#[inline]
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
|
||||
let socket = sys::net::Socket::from_inner(fd);
|
||||
let socket = unsafe { sys::net::Socket::from_raw_fd(fd) };
|
||||
net::$t::from_inner(sys_common::net::$t::from_inner(socket))
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +405,7 @@ macro_rules! impl_into_raw_fd {
|
|||
impl IntoRawFd for net::$t {
|
||||
#[inline]
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.into_inner().into_socket().into_inner()
|
||||
self.into_inner().into_socket().into_raw_fd()
|
||||
}
|
||||
}
|
||||
)*};
|
||||
|
|
|
@ -13,5 +13,5 @@ pub mod prelude {
|
|||
pub use super::ffi::{OsStrExt, OsStringExt};
|
||||
#[doc(no_inline)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
|
||||
pub use super::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
|
||||
}
|
||||
|
|
|
@ -347,7 +347,7 @@ impl ChildExt for process::Child {
|
|||
///
|
||||
/// This trait is sealed: it cannot be implemented outside the standard library.
|
||||
/// This is so that future additional methods are not breaking changes.
|
||||
#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
|
||||
#[unstable(feature = "windows_process_exit_code_from", issue = "111688")]
|
||||
pub trait ExitCodeExt: Sealed {
|
||||
/// Creates a new `ExitCode` from the raw underlying `u32` return value of
|
||||
/// a process.
|
||||
|
@ -355,11 +355,11 @@ pub trait ExitCodeExt: Sealed {
|
|||
/// The exit code should not be 259, as this conflicts with the `STILL_ACTIVE`
|
||||
/// macro returned from the `GetExitCodeProcess` function to signal that the
|
||||
/// process has yet to run to completion.
|
||||
#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
|
||||
#[unstable(feature = "windows_process_exit_code_from", issue = "111688")]
|
||||
fn from_raw(raw: u32) -> Self;
|
||||
}
|
||||
|
||||
#[unstable(feature = "windows_process_exit_code_from", issue = "none")]
|
||||
#[unstable(feature = "windows_process_exit_code_from", issue = "111688")]
|
||||
impl ExitCodeExt for process::ExitCode {
|
||||
fn from_raw(raw: u32) -> Self {
|
||||
process::ExitCode::from_inner(From::from(raw))
|
||||
|
|
|
@ -5,9 +5,10 @@ use crate::{
|
|||
io::{self, BorrowedBuf, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut},
|
||||
mem,
|
||||
net::{Shutdown, SocketAddr},
|
||||
os::solid::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd},
|
||||
ptr, str,
|
||||
sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr},
|
||||
sys_common::{AsInner, FromInner, IntoInner},
|
||||
sys_common::{FromInner, IntoInner},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
|
@ -28,102 +29,6 @@ const fn max_iov() -> usize {
|
|||
1024
|
||||
}
|
||||
|
||||
/// A file descriptor.
|
||||
#[rustc_layout_scalar_valid_range_start(0)]
|
||||
// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
|
||||
// 32-bit c_int. Below is -2, in two's complement, but that only works out
|
||||
// because c_int is 32 bits.
|
||||
#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
|
||||
struct FileDesc {
|
||||
fd: c_int,
|
||||
}
|
||||
|
||||
impl FileDesc {
|
||||
#[inline]
|
||||
fn new(fd: c_int) -> FileDesc {
|
||||
assert_ne!(fd, -1i32);
|
||||
// Safety: we just asserted that the value is in the valid range and
|
||||
// isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
|
||||
unsafe { FileDesc { fd } }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn raw(&self) -> c_int {
|
||||
self.fd
|
||||
}
|
||||
|
||||
/// Extracts the actual file descriptor without closing it.
|
||||
#[inline]
|
||||
fn into_raw(self) -> c_int {
|
||||
let fd = self.fd;
|
||||
mem::forget(self);
|
||||
fd
|
||||
}
|
||||
|
||||
fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let ret = cvt(unsafe {
|
||||
netc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
|
||||
})?;
|
||||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
let ret = cvt(unsafe {
|
||||
netc::readv(
|
||||
self.fd,
|
||||
bufs.as_ptr() as *const netc::iovec,
|
||||
cmp::min(bufs.len(), max_iov()) as c_int,
|
||||
)
|
||||
})?;
|
||||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_read_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
let ret = cvt(unsafe {
|
||||
netc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
|
||||
})?;
|
||||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
let ret = cvt(unsafe {
|
||||
netc::writev(
|
||||
self.fd,
|
||||
bufs.as_ptr() as *const netc::iovec,
|
||||
cmp::min(bufs.len(), max_iov()) as c_int,
|
||||
)
|
||||
})?;
|
||||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_write_vectored(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn duplicate(&self) -> io::Result<FileDesc> {
|
||||
cvt(unsafe { netc::dup(self.fd) }).map(Self::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<c_int> for FileDesc {
|
||||
#[inline]
|
||||
fn as_inner(&self) -> &c_int {
|
||||
&self.fd
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for FileDesc {
|
||||
fn drop(&mut self) {
|
||||
unsafe { netc::close(self.fd) };
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait IsMinusOne {
|
||||
fn is_minus_one(&self) -> bool;
|
||||
|
@ -212,7 +117,7 @@ pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind {
|
|||
|
||||
pub fn init() {}
|
||||
|
||||
pub struct Socket(FileDesc);
|
||||
pub struct Socket(OwnedFd);
|
||||
|
||||
impl Socket {
|
||||
pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
|
||||
|
@ -226,16 +131,13 @@ impl Socket {
|
|||
pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
|
||||
unsafe {
|
||||
let fd = cvt(netc::socket(fam, ty, 0))?;
|
||||
let fd = FileDesc::new(fd);
|
||||
let socket = Socket(fd);
|
||||
|
||||
Ok(socket)
|
||||
Ok(Self::from_raw_fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> {
|
||||
let (addr, len) = addr.into_inner();
|
||||
cvt(unsafe { netc::connect(self.0.raw(), addr.as_ptr(), len) })?;
|
||||
cvt(unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -264,14 +166,14 @@ impl Socket {
|
|||
timeout.tv_usec = 1;
|
||||
}
|
||||
|
||||
let fds = netc::fd_set { num_fds: 1, fds: [self.0.raw()] };
|
||||
let fds = netc::fd_set { num_fds: 1, fds: [self.as_raw_fd()] };
|
||||
|
||||
let mut writefds = fds;
|
||||
let mut errorfds = fds;
|
||||
|
||||
let n = unsafe {
|
||||
cvt(netc::select(
|
||||
self.0.raw() + 1,
|
||||
self.as_raw_fd() + 1,
|
||||
ptr::null_mut(),
|
||||
&mut writefds,
|
||||
&mut errorfds,
|
||||
|
@ -294,18 +196,17 @@ impl Socket {
|
|||
}
|
||||
|
||||
pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> {
|
||||
let fd = cvt_r(|| unsafe { netc::accept(self.0.raw(), storage, len) })?;
|
||||
let fd = FileDesc::new(fd);
|
||||
Ok(Socket(fd))
|
||||
let fd = cvt_r(|| unsafe { netc::accept(self.as_raw_fd(), storage, len) })?;
|
||||
unsafe { Ok(Self::from_raw_fd(fd)) }
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> io::Result<Socket> {
|
||||
self.0.duplicate().map(Socket)
|
||||
Ok(Self(self.0.try_clone()?))
|
||||
}
|
||||
|
||||
fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> {
|
||||
let ret = cvt(unsafe {
|
||||
netc::recv(self.0.raw(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags)
|
||||
netc::recv(self.as_raw_fd(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags)
|
||||
})?;
|
||||
unsafe {
|
||||
buf.advance(ret as usize);
|
||||
|
@ -330,12 +231,19 @@ impl Socket {
|
|||
}
|
||||
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
self.0.read_vectored(bufs)
|
||||
let ret = cvt(unsafe {
|
||||
netc::readv(
|
||||
self.as_raw_fd(),
|
||||
bufs.as_ptr() as *const netc::iovec,
|
||||
cmp::min(bufs.len(), max_iov()) as c_int,
|
||||
)
|
||||
})?;
|
||||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_read_vectored(&self) -> bool {
|
||||
self.0.is_read_vectored()
|
||||
true
|
||||
}
|
||||
|
||||
fn recv_from_with_flags(
|
||||
|
@ -348,7 +256,7 @@ impl Socket {
|
|||
|
||||
let n = cvt(unsafe {
|
||||
netc::recvfrom(
|
||||
self.0.raw(),
|
||||
self.as_raw_fd(),
|
||||
buf.as_mut_ptr() as *mut c_void,
|
||||
buf.len(),
|
||||
flags,
|
||||
|
@ -368,16 +276,30 @@ impl Socket {
|
|||
}
|
||||
|
||||
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
|
||||
self.0.write(buf)
|
||||
let ret = cvt(unsafe {
|
||||
netc::write(
|
||||
self.as_raw_fd(),
|
||||
buf.as_ptr() as *const c_void,
|
||||
cmp::min(buf.len(), READ_LIMIT),
|
||||
)
|
||||
})?;
|
||||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
self.0.write_vectored(bufs)
|
||||
let ret = cvt(unsafe {
|
||||
netc::writev(
|
||||
self.as_raw_fd(),
|
||||
bufs.as_ptr() as *const netc::iovec,
|
||||
cmp::min(bufs.len(), max_iov()) as c_int,
|
||||
)
|
||||
})?;
|
||||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_write_vectored(&self) -> bool {
|
||||
self.0.is_write_vectored()
|
||||
true
|
||||
}
|
||||
|
||||
pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> {
|
||||
|
@ -423,7 +345,7 @@ impl Socket {
|
|||
Shutdown::Read => netc::SHUT_RD,
|
||||
Shutdown::Both => netc::SHUT_RDWR,
|
||||
};
|
||||
cvt(unsafe { netc::shutdown(self.0.raw(), how) })?;
|
||||
cvt(unsafe { netc::shutdown(self.as_raw_fd(), how) })?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -454,7 +376,7 @@ impl Socket {
|
|||
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
|
||||
let mut nonblocking = nonblocking as c_int;
|
||||
cvt(unsafe {
|
||||
netc::ioctl(*self.as_inner(), netc::FIONBIO, (&mut nonblocking) as *mut c_int as _)
|
||||
netc::ioctl(self.as_raw_fd(), netc::FIONBIO, (&mut nonblocking) as *mut c_int as _)
|
||||
})
|
||||
.map(drop)
|
||||
}
|
||||
|
@ -466,25 +388,48 @@ impl Socket {
|
|||
|
||||
// This method is used by sys_common code to abstract over targets.
|
||||
pub fn as_raw(&self) -> c_int {
|
||||
*self.as_inner()
|
||||
self.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<c_int> for Socket {
|
||||
impl FromInner<OwnedFd> for Socket {
|
||||
#[inline]
|
||||
fn as_inner(&self) -> &c_int {
|
||||
self.0.as_inner()
|
||||
fn from_inner(sock: OwnedFd) -> Socket {
|
||||
Socket(sock)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromInner<c_int> for Socket {
|
||||
fn from_inner(fd: c_int) -> Socket {
|
||||
Socket(FileDesc::new(fd))
|
||||
impl IntoInner<OwnedFd> for Socket {
|
||||
#[inline]
|
||||
fn into_inner(self) -> OwnedFd {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoInner<c_int> for Socket {
|
||||
fn into_inner(self) -> c_int {
|
||||
self.0.into_raw()
|
||||
impl AsFd for Socket {
|
||||
#[inline]
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
self.0.as_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Socket {
|
||||
#[inline]
|
||||
fn as_raw_fd(&self) -> c_int {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl FromRawFd for Socket {
|
||||
#[inline]
|
||||
unsafe fn from_raw_fd(fd: c_int) -> Socket {
|
||||
unsafe { Self(FromRawFd::from_raw_fd(fd)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for Socket {
|
||||
#[inline]
|
||||
fn into_raw_fd(self) -> c_int {
|
||||
self.0.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,8 @@ pub use FD_SET as fd_set;
|
|||
pub use LINGER as linger;
|
||||
pub use TIMEVAL as timeval;
|
||||
|
||||
pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::invalid_mut(-1i32 as _);
|
||||
|
||||
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170
|
||||
pub const EXIT_SUCCESS: u32 = 0;
|
||||
pub const EXIT_FAILURE: u32 = 1;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
--config flatten std
|
||||
--filter
|
||||
// tidy-alphabetical-start
|
||||
!Windows.Win32.Foundation.INVALID_HANDLE_VALUE
|
||||
Windows.Wdk.Storage.FileSystem.FILE_COMPLETE_IF_OPLOCKED
|
||||
Windows.Wdk.Storage.FileSystem.FILE_CONTAINS_EXTENDED_CREATE_INFORMATION
|
||||
Windows.Wdk.Storage.FileSystem.FILE_CREATE
|
||||
|
@ -1923,7 +1924,6 @@ Windows.Win32.Foundation.HANDLE_FLAG_INHERIT
|
|||
Windows.Win32.Foundation.HANDLE_FLAG_PROTECT_FROM_CLOSE
|
||||
Windows.Win32.Foundation.HANDLE_FLAGS
|
||||
Windows.Win32.Foundation.HMODULE
|
||||
Windows.Win32.Foundation.INVALID_HANDLE_VALUE
|
||||
Windows.Win32.Foundation.MAX_PATH
|
||||
Windows.Win32.Foundation.NO_ERROR
|
||||
Windows.Win32.Foundation.NTSTATUS
|
||||
|
@ -2483,7 +2483,6 @@ Windows.Win32.System.SystemInformation.GetSystemTimeAsFileTime
|
|||
Windows.Win32.System.SystemInformation.GetWindowsDirectoryW
|
||||
Windows.Win32.System.SystemInformation.PROCESSOR_ARCHITECTURE
|
||||
Windows.Win32.System.SystemInformation.SYSTEM_INFO
|
||||
Windows.Win32.System.SystemServices.ALL_PROCESSOR_GROUPS
|
||||
Windows.Win32.System.SystemServices.DLL_PROCESS_DETACH
|
||||
Windows.Win32.System.SystemServices.DLL_THREAD_DETACH
|
||||
Windows.Win32.System.SystemServices.EXCEPTION_MAXIMUM_PARAMETERS
|
||||
|
@ -2492,6 +2491,7 @@ Windows.Win32.System.SystemServices.IO_REPARSE_TAG_SYMLINK
|
|||
Windows.Win32.System.Threading.ABOVE_NORMAL_PRIORITY_CLASS
|
||||
Windows.Win32.System.Threading.AcquireSRWLockExclusive
|
||||
Windows.Win32.System.Threading.AcquireSRWLockShared
|
||||
Windows.Win32.System.Threading.ALL_PROCESSOR_GROUPS
|
||||
Windows.Win32.System.Threading.BELOW_NORMAL_PRIORITY_CLASS
|
||||
Windows.Win32.System.Threading.CREATE_BREAKAWAY_FROM_JOB
|
||||
Windows.Win32.System.Threading.CREATE_DEFAULT_ERROR_MODE
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// regenerate the bindings.
|
||||
//
|
||||
// ignore-tidy-filelength
|
||||
// Bindings generated by `windows-bindgen` 0.51.1
|
||||
// Bindings generated by `windows-bindgen` 0.52.0
|
||||
|
||||
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
|
||||
#[link(name = "advapi32")]
|
||||
|
@ -63,7 +63,7 @@ extern "system" {
|
|||
lpnewfilename: PCWSTR,
|
||||
lpprogressroutine: LPPROGRESS_ROUTINE,
|
||||
lpdata: *const ::core::ffi::c_void,
|
||||
pbcancel: *mut i32,
|
||||
pbcancel: *mut BOOL,
|
||||
dwcopyflags: u32,
|
||||
) -> BOOL;
|
||||
}
|
||||
|
@ -619,7 +619,7 @@ extern "system" {
|
|||
lpmultibytestr: PSTR,
|
||||
cbmultibyte: i32,
|
||||
lpdefaultchar: PCSTR,
|
||||
lpuseddefaultchar: *mut i32,
|
||||
lpuseddefaultchar: *mut BOOL,
|
||||
) -> i32;
|
||||
}
|
||||
#[link(name = "kernel32")]
|
||||
|
@ -869,7 +869,7 @@ pub const AF_INET: ADDRESS_FAMILY = 2u16;
|
|||
pub const AF_INET6: ADDRESS_FAMILY = 23u16;
|
||||
pub const AF_UNIX: u16 = 1u16;
|
||||
pub const AF_UNSPEC: ADDRESS_FAMILY = 0u16;
|
||||
pub const ALL_PROCESSOR_GROUPS: u32 = 65535u32;
|
||||
pub const ALL_PROCESSOR_GROUPS: u16 = 65535u16;
|
||||
#[repr(C)]
|
||||
pub union ARM64_NT_NEON128 {
|
||||
pub Anonymous: ARM64_NT_NEON128_0,
|
||||
|
@ -3498,7 +3498,6 @@ impl ::core::clone::Clone for INIT_ONCE {
|
|||
}
|
||||
pub const INIT_ONCE_INIT_FAILED: u32 = 4u32;
|
||||
pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32;
|
||||
pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::invalid_mut(-1i32 as _);
|
||||
pub const INVALID_SOCKET: SOCKET = -1i32 as _;
|
||||
#[repr(C)]
|
||||
pub struct IN_ADDR {
|
||||
|
|
|
@ -597,7 +597,7 @@ impl Stdio {
|
|||
opts.read(stdio_id == c::STD_INPUT_HANDLE);
|
||||
opts.write(stdio_id != c::STD_INPUT_HANDLE);
|
||||
opts.security_attributes(&mut sa);
|
||||
File::open(Path::new("NUL"), &opts).map(|file| file.into_inner())
|
||||
File::open(Path::new(r"\\.\NUL"), &opts).map(|file| file.into_inner())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,4 +39,5 @@ ignore = [
|
|||
# these are ignored by a standard cargo fmt run
|
||||
"compiler/rustc_codegen_cranelift/y.rs", # running rustfmt breaks this file
|
||||
"compiler/rustc_codegen_cranelift/scripts",
|
||||
"compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs", # uses edition 2024
|
||||
]
|
||||
|
|
|
@ -9,11 +9,14 @@
|
|||
use std::io::Write;
|
||||
#[cfg(all(any(unix, windows), not(target_os = "solaris")))]
|
||||
use std::process;
|
||||
use std::{env, fs};
|
||||
use std::{
|
||||
env, fs,
|
||||
io::{self, IsTerminal},
|
||||
};
|
||||
|
||||
#[cfg(all(any(unix, windows), not(target_os = "solaris")))]
|
||||
use bootstrap::t;
|
||||
use bootstrap::{find_recent_config_change_ids, Build, Config, Subcommand, CONFIG_CHANGE_HISTORY};
|
||||
use bootstrap::{
|
||||
find_recent_config_change_ids, t, Build, Config, Subcommand, CONFIG_CHANGE_HISTORY,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
let args = env::args().skip(1).collect::<Vec<_>>();
|
||||
|
@ -108,35 +111,46 @@ fn check_version(config: &Config) -> Option<String> {
|
|||
msg.push_str("WARNING: The use of `changelog-seen` is deprecated. Please refer to `change-id` option in `config.example.toml` instead.\n");
|
||||
}
|
||||
|
||||
let latest_config_id = CONFIG_CHANGE_HISTORY.last().unwrap();
|
||||
let latest_change_id = CONFIG_CHANGE_HISTORY.last().unwrap().change_id;
|
||||
let warned_id_path = config.out.join("bootstrap").join(".last-warned-change-id");
|
||||
|
||||
if let Some(id) = config.change_id {
|
||||
if &id == latest_config_id {
|
||||
if id == latest_change_id {
|
||||
return None;
|
||||
}
|
||||
|
||||
let change_links: Vec<String> = find_recent_config_change_ids(id)
|
||||
.iter()
|
||||
.map(|id| format!("https://github.com/rust-lang/rust/pull/{id}"))
|
||||
.collect();
|
||||
if !change_links.is_empty() {
|
||||
msg.push_str("WARNING: there have been changes to x.py since you last updated.\n");
|
||||
msg.push_str("To see more detail about these changes, visit the following PRs:\n");
|
||||
|
||||
for link in change_links {
|
||||
msg.push_str(&format!(" - {link}\n"));
|
||||
if let Ok(last_warned_id) = fs::read_to_string(&warned_id_path) {
|
||||
if id.to_string() == last_warned_id {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
msg.push_str("WARNING: there have been changes to x.py since you last updated.\n");
|
||||
let changes = find_recent_config_change_ids(id);
|
||||
|
||||
if !changes.is_empty() {
|
||||
msg.push_str("There have been changes to x.py since you last updated:\n");
|
||||
|
||||
for change in changes {
|
||||
msg.push_str(&format!(" [{}] {}\n", change.severity.to_string(), change.summary));
|
||||
msg.push_str(&format!(
|
||||
" - PR Link https://github.com/rust-lang/rust/pull/{}\n",
|
||||
change.change_id
|
||||
));
|
||||
}
|
||||
|
||||
msg.push_str("NOTE: to silence this warning, ");
|
||||
msg.push_str(&format!(
|
||||
"update `config.toml` to use `change-id = {latest_config_id}` instead"
|
||||
"update `config.toml` to use `change-id = {latest_change_id}` instead"
|
||||
));
|
||||
|
||||
if io::stdout().is_terminal() {
|
||||
t!(fs::write(warned_id_path, id.to_string()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
msg.push_str("WARNING: The `change-id` is missing in the `config.toml`. This means that you will not be able to track the major changes made to the bootstrap configurations.\n");
|
||||
msg.push_str("NOTE: to silence this warning, ");
|
||||
msg.push_str(&format!("add `change-id = {latest_config_id}` at the top of `config.toml`"));
|
||||
msg.push_str(&format!("add `change-id = {latest_change_id}` at the top of `config.toml`"));
|
||||
};
|
||||
|
||||
Some(msg)
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
//! See comments in `src/bootstrap/rustc.rs` for more information.
|
||||
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
|
@ -52,15 +51,6 @@ fn main() {
|
|||
if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() {
|
||||
cmd.arg("-Z").arg("force-unstable-if-unmarked");
|
||||
}
|
||||
if let Some(linker) = env::var_os("RUSTDOC_LINKER") {
|
||||
let mut arg = OsString::from("-Clinker=");
|
||||
arg.push(&linker);
|
||||
cmd.arg(arg);
|
||||
}
|
||||
if let Ok(no_threads) = env::var("RUSTDOC_LLD_NO_THREADS") {
|
||||
cmd.arg("-Clink-arg=-fuse-ld=lld");
|
||||
cmd.arg(format!("-Clink-arg=-Wl,{no_threads}"));
|
||||
}
|
||||
// Cargo doesn't pass RUSTDOCFLAGS to proc_macros:
|
||||
// https://github.com/rust-lang/cargo/issues/4423
|
||||
// Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`.
|
||||
|
|
|
@ -145,6 +145,7 @@ fn clean_specific_stage(build: &Build, stage: u32) {
|
|||
fn clean_default(build: &Build) {
|
||||
rm_rf(&build.out.join("tmp"));
|
||||
rm_rf(&build.out.join("dist"));
|
||||
rm_rf(&build.out.join("bootstrap").join(".last-warned-change-id"));
|
||||
rm_rf(&build.out.join("rustfmt.stamp"));
|
||||
|
||||
for host in &build.hosts {
|
||||
|
|
|
@ -142,14 +142,17 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) {
|
|||
};
|
||||
if in_working_tree {
|
||||
let untracked_paths_output = output(
|
||||
build.config.git().arg("status").arg("--porcelain").arg("--untracked-files=normal"),
|
||||
build
|
||||
.config
|
||||
.git()
|
||||
.arg("status")
|
||||
.arg("--porcelain")
|
||||
.arg("-z")
|
||||
.arg("--untracked-files=normal"),
|
||||
);
|
||||
let untracked_paths = untracked_paths_output.split_terminator('\0').filter_map(
|
||||
|entry| entry.strip_prefix("?? "), // returns None if the prefix doesn't match
|
||||
);
|
||||
let untracked_paths = untracked_paths_output
|
||||
.lines()
|
||||
.filter(|entry| entry.starts_with("??"))
|
||||
.map(|entry| {
|
||||
entry.split(' ').nth(1).expect("every git status entry should list a path")
|
||||
});
|
||||
let mut untracked_count = 0;
|
||||
for untracked_path in untracked_paths {
|
||||
println!("skip untracked path {untracked_path} during rustfmt invocations");
|
||||
|
|
|
@ -20,7 +20,7 @@ use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
|
|||
use crate::core::config::{Config, TargetSelection};
|
||||
use crate::utils::channel;
|
||||
use crate::utils::helpers::{self, exe, get_clang_cl_resource_dir, output, t, up_to_date};
|
||||
use crate::{CLang, GitRepo, Kind};
|
||||
use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind};
|
||||
|
||||
use build_helper::ci::CiEnv;
|
||||
use build_helper::git::get_git_merge_base;
|
||||
|
@ -105,8 +105,13 @@ pub fn prebuilt_llvm_config(
|
|||
let llvm_cmake_dir = out_dir.join("lib/cmake/llvm");
|
||||
let res = LlvmResult { llvm_config: build_llvm_config, llvm_cmake_dir };
|
||||
|
||||
let smart_stamp_hash = generate_smart_stamp_hash(
|
||||
&builder.config.src.join("src/llvm-project"),
|
||||
&builder.in_tree_llvm_info.sha().unwrap_or_default(),
|
||||
);
|
||||
|
||||
let stamp = out_dir.join("llvm-finished-building");
|
||||
let stamp = HashStamp::new(stamp, builder.in_tree_llvm_info.sha());
|
||||
let stamp = HashStamp::new(stamp, Some(&smart_stamp_hash));
|
||||
|
||||
if stamp.is_done() {
|
||||
if stamp.hash.is_none() {
|
||||
|
|
|
@ -226,7 +226,7 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) {
|
|||
return;
|
||||
}
|
||||
|
||||
let latest_change_id = CONFIG_CHANGE_HISTORY.last().unwrap();
|
||||
let latest_change_id = CONFIG_CHANGE_HISTORY.last().unwrap().change_id;
|
||||
let settings = format!(
|
||||
"# Includes one of the default files in src/bootstrap/defaults\n\
|
||||
profile = \"{profile}\"\n\
|
||||
|
|
|
@ -29,8 +29,8 @@ use crate::utils;
|
|||
use crate::utils::cache::{Interned, INTERNER};
|
||||
use crate::utils::exec::BootstrapCommand;
|
||||
use crate::utils::helpers::{
|
||||
self, add_link_lib_path, dylib_path, dylib_path_var, output, t,
|
||||
target_supports_cranelift_backend, up_to_date,
|
||||
self, add_link_lib_path, add_rustdoc_cargo_lld_flags, add_rustdoc_lld_flags, dylib_path,
|
||||
dylib_path_var, output, t, target_supports_cranelift_backend, up_to_date, LldThreads,
|
||||
};
|
||||
use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
|
||||
use crate::{envify, CLang, DocTests, GitRepo, Mode};
|
||||
|
@ -271,13 +271,14 @@ impl Step for Cargotest {
|
|||
|
||||
let _time = helpers::timeit(&builder);
|
||||
let mut cmd = builder.tool_cmd(Tool::CargoTest);
|
||||
builder.run_delaying_failure(
|
||||
cmd.arg(&cargo)
|
||||
let mut cmd = cmd
|
||||
.arg(&cargo)
|
||||
.arg(&out_dir)
|
||||
.args(builder.config.test_args())
|
||||
.env("RUSTC", builder.rustc(compiler))
|
||||
.env("RUSTDOC", builder.rustdoc(compiler)),
|
||||
);
|
||||
.env("RUSTDOC", builder.rustdoc(compiler));
|
||||
add_rustdoc_cargo_lld_flags(&mut cmd, builder, compiler.host, LldThreads::No);
|
||||
builder.run_delaying_failure(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -862,15 +863,8 @@ impl Step for RustdocTheme {
|
|||
.env("CFG_RELEASE_CHANNEL", &builder.config.channel)
|
||||
.env("RUSTDOC_REAL", builder.rustdoc(self.compiler))
|
||||
.env("RUSTC_BOOTSTRAP", "1");
|
||||
if let Some(linker) = builder.linker(self.compiler.host) {
|
||||
cmd.env("RUSTDOC_LINKER", linker);
|
||||
}
|
||||
if builder.is_fuse_ld_lld(self.compiler.host) {
|
||||
cmd.env(
|
||||
"RUSTDOC_LLD_NO_THREADS",
|
||||
helpers::lld_flag_no_threads(self.compiler.host.contains("windows")),
|
||||
);
|
||||
}
|
||||
add_rustdoc_lld_flags(&mut cmd, builder, self.compiler.host, LldThreads::No);
|
||||
|
||||
builder.run_delaying_failure(&mut cmd);
|
||||
}
|
||||
}
|
||||
|
@ -1044,6 +1038,8 @@ impl Step for RustdocGUI {
|
|||
cmd.env("RUSTDOC", builder.rustdoc(self.compiler))
|
||||
.env("RUSTC", builder.rustc(self.compiler));
|
||||
|
||||
add_rustdoc_cargo_lld_flags(&mut cmd, builder, self.compiler.host, LldThreads::No);
|
||||
|
||||
for path in &builder.paths {
|
||||
if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) {
|
||||
if !p.ends_with(".goml") {
|
||||
|
|
|
@ -18,7 +18,8 @@ use crate::core::build_steps::{check, clean, compile, dist, doc, install, run, s
|
|||
use crate::core::config::flags::{Color, Subcommand};
|
||||
use crate::core::config::{DryRun, SplitDebuginfo, TargetSelection};
|
||||
use crate::utils::cache::{Cache, Interned, INTERNER};
|
||||
use crate::utils::helpers::{self, add_dylib_path, add_link_lib_path, exe, libdir, output, t};
|
||||
use crate::utils::helpers::{self, add_dylib_path, add_link_lib_path, add_rustdoc_lld_flags, exe};
|
||||
use crate::utils::helpers::{libdir, output, t, LldThreads};
|
||||
use crate::Crate;
|
||||
use crate::EXTRA_CHECK_CFGS;
|
||||
use crate::{Build, CLang, DocTests, GitRepo, Mode};
|
||||
|
@ -1174,9 +1175,7 @@ impl<'a> Builder<'a> {
|
|||
cmd.env_remove("MAKEFLAGS");
|
||||
cmd.env_remove("MFLAGS");
|
||||
|
||||
if let Some(linker) = self.linker(compiler.host) {
|
||||
cmd.env("RUSTDOC_LINKER", linker);
|
||||
}
|
||||
add_rustdoc_lld_flags(&mut cmd, self, compiler.host, LldThreads::Yes);
|
||||
cmd
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ use build_helper::exit;
|
|||
use build_helper::util::fail;
|
||||
use filetime::FileTime;
|
||||
use once_cell::sync::OnceCell;
|
||||
use sha2::digest::Digest;
|
||||
use termcolor::{ColorChoice, StandardStream, WriteColor};
|
||||
use utils::channel::GitInfo;
|
||||
|
||||
|
@ -69,16 +70,61 @@ const LLVM_TOOLS: &[&str] = &[
|
|||
/// LLD file names for all flavors.
|
||||
const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"];
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ChangeInfo {
|
||||
/// Represents the ID of PR caused major change on bootstrap.
|
||||
pub change_id: usize,
|
||||
pub severity: ChangeSeverity,
|
||||
/// Provides a short summary of the change that will guide developers
|
||||
/// on "how to handle/behave" in response to the changes.
|
||||
pub summary: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ChangeSeverity {
|
||||
/// Used when build configurations continue working as before.
|
||||
Info,
|
||||
/// Used when the default value of an option changes, or support for an option is removed entirely,
|
||||
/// potentially requiring developers to update their build configurations.
|
||||
Warning,
|
||||
}
|
||||
|
||||
impl ToString for ChangeSeverity {
|
||||
fn to_string(&self) -> String {
|
||||
match self {
|
||||
ChangeSeverity::Info => "INFO".to_string(),
|
||||
ChangeSeverity::Warning => "WARNING".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Keeps track of major changes made to the bootstrap configuration.
|
||||
///
|
||||
/// These values also represent the IDs of the PRs that caused major changes.
|
||||
/// You can visit `https://github.com/rust-lang/rust/pull/{any-id-from-the-list}` to
|
||||
/// check for more details regarding each change.
|
||||
///
|
||||
/// If you make any major changes (such as adding new values or changing default values),
|
||||
/// please ensure that the associated PR ID is added to the end of this list.
|
||||
/// This is necessary because the list must be sorted by the merge date.
|
||||
pub const CONFIG_CHANGE_HISTORY: &[usize] = &[115898, 116998, 117435, 116881];
|
||||
/// please ensure adding `ChangeInfo` to the end(because the list must be sorted by the merge date)
|
||||
/// of this list.
|
||||
pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
|
||||
ChangeInfo {
|
||||
change_id: 115898,
|
||||
severity: ChangeSeverity::Info,
|
||||
summary: "Implementation of this change-tracking system. Ignore this.",
|
||||
},
|
||||
ChangeInfo {
|
||||
change_id: 116998,
|
||||
severity: ChangeSeverity::Info,
|
||||
summary: "Removed android-ndk r15 support in favor of android-ndk r25b.",
|
||||
},
|
||||
ChangeInfo {
|
||||
change_id: 117435,
|
||||
severity: ChangeSeverity::Info,
|
||||
summary: "New option `rust.parallel-compiler` added to config.toml.",
|
||||
},
|
||||
ChangeInfo {
|
||||
change_id: 116881,
|
||||
severity: ChangeSeverity::Warning,
|
||||
summary: "Default value of `download-ci-llvm` was changed for `codegen` profile.",
|
||||
},
|
||||
];
|
||||
|
||||
/// Extra --check-cfg to add when building
|
||||
/// (Mode restriction, config name, config values (if any))
|
||||
|
@ -1849,14 +1895,14 @@ fn envify(s: &str) -> String {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub fn find_recent_config_change_ids(current_id: usize) -> Vec<usize> {
|
||||
if !CONFIG_CHANGE_HISTORY.contains(¤t_id) {
|
||||
pub fn find_recent_config_change_ids(current_id: usize) -> Vec<ChangeInfo> {
|
||||
if !CONFIG_CHANGE_HISTORY.iter().any(|config| config.change_id == current_id) {
|
||||
// If the current change-id is greater than the most recent one, return
|
||||
// an empty list (it may be due to switching from a recent branch to an
|
||||
// older one); otherwise, return the full list (assuming the user provided
|
||||
// the incorrect change-id by accident).
|
||||
if let Some(max_id) = CONFIG_CHANGE_HISTORY.iter().max() {
|
||||
if ¤t_id > max_id {
|
||||
if let Some(config) = CONFIG_CHANGE_HISTORY.iter().max_by_key(|config| config.change_id) {
|
||||
if ¤t_id > &config.change_id {
|
||||
return Vec::new();
|
||||
}
|
||||
}
|
||||
|
@ -1864,7 +1910,8 @@ pub fn find_recent_config_change_ids(current_id: usize) -> Vec<usize> {
|
|||
return CONFIG_CHANGE_HISTORY.to_vec();
|
||||
}
|
||||
|
||||
let index = CONFIG_CHANGE_HISTORY.iter().position(|&id| id == current_id).unwrap();
|
||||
let index =
|
||||
CONFIG_CHANGE_HISTORY.iter().position(|config| config.change_id == current_id).unwrap();
|
||||
|
||||
CONFIG_CHANGE_HISTORY
|
||||
.iter()
|
||||
|
@ -1872,3 +1919,45 @@ pub fn find_recent_config_change_ids(current_id: usize) -> Vec<usize> {
|
|||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Computes a hash representing the state of a repository/submodule and additional input.
|
||||
///
|
||||
/// It uses `git diff` for the actual changes, and `git status` for including the untracked
|
||||
/// files in the specified directory. The additional input is also incorporated into the
|
||||
/// computation of the hash.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `dir`: A reference to the directory path of the target repository/submodule.
|
||||
/// - `additional_input`: An additional input to be included in the hash.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// In case of errors during `git` command execution (e.g., in tarball sources), default values
|
||||
/// are used to prevent panics.
|
||||
pub fn generate_smart_stamp_hash(dir: &Path, additional_input: &str) -> String {
|
||||
let diff = Command::new("git")
|
||||
.current_dir(dir)
|
||||
.arg("diff")
|
||||
.output()
|
||||
.map(|o| String::from_utf8(o.stdout).unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
|
||||
let status = Command::new("git")
|
||||
.current_dir(dir)
|
||||
.arg("status")
|
||||
.arg("--porcelain")
|
||||
.arg("-z")
|
||||
.arg("--untracked-files=normal")
|
||||
.output()
|
||||
.map(|o| String::from_utf8(o.stdout).unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
|
||||
hasher.update(diff);
|
||||
hasher.update(status);
|
||||
hasher.update(additional_input);
|
||||
|
||||
hex::encode(hasher.finalize().as_slice())
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
use build_helper::util::fail;
|
||||
use std::env;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -377,7 +378,6 @@ fn absolute_unix(path: &Path) -> io::Result<PathBuf> {
|
|||
|
||||
#[cfg(windows)]
|
||||
fn absolute_windows(path: &std::path::Path) -> std::io::Result<std::path::PathBuf> {
|
||||
use std::ffi::OsString;
|
||||
use std::io::Error;
|
||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
use std::ptr::null_mut;
|
||||
|
@ -470,3 +470,64 @@ pub fn extract_beta_rev(version: &str) -> Option<String> {
|
|||
|
||||
count
|
||||
}
|
||||
|
||||
pub enum LldThreads {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
pub fn add_rustdoc_lld_flags(
|
||||
cmd: &mut Command,
|
||||
builder: &Builder<'_>,
|
||||
target: TargetSelection,
|
||||
lld_threads: LldThreads,
|
||||
) {
|
||||
cmd.args(build_rustdoc_lld_flags(builder, target, lld_threads));
|
||||
}
|
||||
|
||||
pub fn add_rustdoc_cargo_lld_flags(
|
||||
cmd: &mut Command,
|
||||
builder: &Builder<'_>,
|
||||
target: TargetSelection,
|
||||
lld_threads: LldThreads,
|
||||
) {
|
||||
let args = build_rustdoc_lld_flags(builder, target, lld_threads);
|
||||
let mut flags = cmd
|
||||
.get_envs()
|
||||
.find_map(|(k, v)| if k == OsStr::new("RUSTDOCFLAGS") { v } else { None })
|
||||
.unwrap_or_default()
|
||||
.to_os_string();
|
||||
for arg in args {
|
||||
if !flags.is_empty() {
|
||||
flags.push(" ");
|
||||
}
|
||||
flags.push(arg);
|
||||
}
|
||||
if !flags.is_empty() {
|
||||
cmd.env("RUSTDOCFLAGS", flags);
|
||||
}
|
||||
}
|
||||
|
||||
fn build_rustdoc_lld_flags(
|
||||
builder: &Builder<'_>,
|
||||
target: TargetSelection,
|
||||
lld_threads: LldThreads,
|
||||
) -> Vec<OsString> {
|
||||
let mut args = vec![];
|
||||
|
||||
if let Some(linker) = builder.linker(target) {
|
||||
let mut flag = std::ffi::OsString::from("-Clinker=");
|
||||
flag.push(linker);
|
||||
args.push(flag);
|
||||
}
|
||||
if builder.is_fuse_ld_lld(target) {
|
||||
args.push(OsString::from("-Clink-arg=-fuse-ld=lld"));
|
||||
if matches!(lld_threads, LldThreads::No) {
|
||||
args.push(OsString::from(format!(
|
||||
"-Clink-arg=-Wl,{}",
|
||||
lld_flag_no_threads(target.contains("windows"))
|
||||
)));
|
||||
}
|
||||
}
|
||||
args
|
||||
}
|
||||
|
|
|
@ -369,8 +369,8 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items:
|
|||
if let (Some(a), Some(b)) = (s1, s2) {
|
||||
match (a.is_stable(), b.is_stable()) {
|
||||
(true, true) | (false, false) => {}
|
||||
(false, true) => return Ordering::Less,
|
||||
(true, false) => return Ordering::Greater,
|
||||
(false, true) => return Ordering::Greater,
|
||||
(true, false) => return Ordering::Less,
|
||||
}
|
||||
}
|
||||
let lhs = i1.name.unwrap_or(kw::Empty);
|
||||
|
@ -1501,8 +1501,10 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>(
|
|||
s: &'a [clean::Item],
|
||||
) -> impl fmt::Display + 'a + Captures<'cx> {
|
||||
display_fn(|f| {
|
||||
if s.iter()
|
||||
.all(|field| matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..))))
|
||||
if !s.is_empty()
|
||||
&& s.iter().all(|field| {
|
||||
matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))
|
||||
})
|
||||
{
|
||||
return f.write_str("/* private fields */");
|
||||
}
|
||||
|
@ -2275,9 +2277,11 @@ fn render_struct_fields(
|
|||
}
|
||||
Some(CtorKind::Fn) => {
|
||||
w.write_str("(");
|
||||
if fields.iter().all(|field| {
|
||||
if !fields.is_empty()
|
||||
&& fields.iter().all(|field| {
|
||||
matches!(*field.kind, clean::StrippedItem(box clean::StructFieldItem(..)))
|
||||
}) {
|
||||
})
|
||||
{
|
||||
write!(w, "/* private fields */");
|
||||
} else {
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
|
|
|
@ -18,5 +18,5 @@ LL | #![deny(clippy::internal)]
|
|||
= note: `#[deny(clippy::default_deprecation_reason)]` implied by `#[deny(clippy::internal)]`
|
||||
= note: this error originates in the macro `declare_deprecated_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -17,5 +17,5 @@ LL | #![deny(clippy::internal)]
|
|||
= note: `#[deny(clippy::default_lint)]` implied by `#[deny(clippy::internal)]`
|
||||
= note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -17,5 +17,5 @@ LL | #![deny(clippy::internal)]
|
|||
= note: `#[deny(clippy::lint_without_lint_pass)]` implied by `#[deny(clippy::internal)]`
|
||||
= note: this error originates in the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -11,5 +11,5 @@ LL | #![deny(clippy::internal)]
|
|||
| ^^^^^^^^^^^^^^^^
|
||||
= note: `#[deny(clippy::outer_expn_expn_data)]` implied by `#[deny(clippy::internal)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@ error: error reading Clippy's configuration file: expected `.`, `=`
|
|||
LL | fn this_is_obviously(not: a, toml: file) {
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@ error: error reading Clippy's configuration file: invalid type: integer `42`, ex
|
|||
LL | disallowed-names = 42
|
||||
| ^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -20,5 +20,5 @@ LL | fn cognitive_complexity() {
|
|||
= note: `-D clippy::cognitive-complexity` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::cognitive_complexity)]`
|
||||
|
||||
error: aborting due to previous error; 2 warnings emitted
|
||||
error: aborting due to 1 previous error; 2 warnings emitted
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@ LL | let _ = 16777215;
|
|||
= note: `-D clippy::decimal-literal-representation` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::decimal_literal_representation)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@ LL | let ducks = ["quack", "quack"];
|
|||
= note: `-D clippy::disallowed-names` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::disallowed_names)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@ LL | let カウンタ = 10;
|
|||
= note: `-D clippy::disallowed-script-idents` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::disallowed_script_idents)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -11,5 +11,5 @@ help: try
|
|||
LL | /// `TestItemThingyOfCoolness` might sound cool but is not on the list and should be linted.
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@ error: error reading Clippy's configuration file: duplicate key `cognitive-compl
|
|||
LL | cognitive-complexity-threshold = 4
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -10,5 +10,5 @@ warning: error reading Clippy's configuration file: deprecated field `cyclomatic
|
|||
LL | cyclomatic-complexity-threshold = 3
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
|
|
|
@ -10,5 +10,5 @@ warning: error reading Clippy's configuration file: deprecated field `cyclomatic
|
|||
LL | cyclomatic-complexity-threshold = 3
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
error: aborting due to 1 previous error; 1 warning emitted
|
||||
|
||||
|
|
|
@ -17,5 +17,5 @@ help: consider boxing the large fields to reduce the total size of the enum
|
|||
LL | B(Box<[u8; 501]>),
|
||||
| ~~~~~~~~~~~~~~
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -8,5 +8,5 @@ LL | fn g(_: bool, _: bool) {}
|
|||
= note: `-D clippy::fn-params-excessive-bools` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::fn_params_excessive_bools)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -12,5 +12,5 @@ LL | if x.get() {
|
|||
= note: `-D clippy::ifs-same-cond` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::ifs_same_cond)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -11,5 +11,5 @@ help: add a type parameter
|
|||
LL | fn t<{ /* Generic name */ }: Trait>(_: impl Trait);
|
||||
| +++++++++++++++++++++++++++++++
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@ error: error reading Clippy's configuration file: not a valid Rust version
|
|||
LL | msrv = "invalid.version"
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@ LL | should_warn().await;
|
|||
= note: `-D clippy::large-futures` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::large_futures)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -11,5 +11,5 @@ LL | | }
|
|||
= note: `-D clippy::large-stack-frames` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@ LL | fn f2(_v: [u8; 513]) {}
|
|||
= note: `-D clippy::large-types-passed-by-value` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::large_types_passed_by_value)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
|
@ -11,5 +11,5 @@ LL | | };
|
|||
= note: `-D clippy::manual-let-else` implied by `-D warnings`
|
||||
= help: to override `-D warnings` add `#[allow(clippy::manual_let_else)]`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue