Auto merge of #3187 - RalfJung:rustup, r=RalfJung

Rustup
This commit is contained in:
bors 2023-11-25 07:29:08 +00:00
commit b7912d38b1
5902 changed files with 7653 additions and 6350 deletions

View file

@ -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"

View file

@ -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);

View file

@ -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 {

View file

@ -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 {

View file

@ -1515,7 +1515,7 @@ impl<'a> State<'a> {
TraitBoundModifier::Maybe => {
self.word("?");
}
TraitBoundModifier::MaybeConst => {
TraitBoundModifier::MaybeConst(_) => {
self.word_space("~const");
}
TraitBoundModifier::MaybeConstNegative => {

View file

@ -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 {

View file

@ -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(

View file

@ -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

View file

@ -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);
}

View file

@ -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"

View file

@ -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.

View file

@ -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,
}
}

View file

@ -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() {

View file

@ -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
},

View file

@ -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.

View file

@ -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,

View file

@ -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
}
}
}

View file

@ -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, || {

View file

@ -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

View file

@ -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,
},
);
}
}

View file

@ -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,

View file

@ -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

View file

@ -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;

View file

@ -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())
()
),)*
}

View file

@ -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)

View file

@ -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.

View file

@ -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);

View file

@ -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(),
}

View file

@ -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)
}
};

View file

@ -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(())

View file

@ -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.

View file

@ -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,
}

View file

@ -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

View file

@ -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)>,

View file

@ -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;

View file

@ -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>,

View file

@ -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 {

View file

@ -787,6 +787,7 @@ symbols! {
fmt,
fmul_fast,
fn_align,
fn_delegation,
fn_must_use,
fn_mut,
fn_once,

View file

@ -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 {

View file

@ -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)]

View file

@ -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(

View file

@ -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);

View file

@ -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> {

View file

@ -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),
}

View 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
}
}
};
}

View file

@ -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

View file

@ -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;

View file

@ -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};

View file

@ -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)]

View file

@ -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.

View file

@ -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
///
/// ```

View file

@ -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.

View file

@ -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`.
//! ```

View file

@ -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

View file

@ -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);

View file

@ -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.
///

View file

@ -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"[..]);

View file

@ -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()
}
}
)*};

View file

@ -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};
}

View file

@ -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))

View file

@ -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()
}
}

View file

@ -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;

View file

@ -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

View file

@ -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 {

View file

@ -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())
}
}
}

View file

@ -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
]

View file

@ -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)

View file

@ -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`.

View file

@ -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 {

View file

@ -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");

View file

@ -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() {

View file

@ -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\

View file

@ -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") {

View file

@ -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
}

View file

@ -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(&current_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 &current_id > max_id {
if let Some(config) = CONFIG_CHANGE_HISTORY.iter().max_by_key(|config| config.change_id) {
if &current_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())
}

View file

@ -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
}

View file

@ -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() {

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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