Merge from rustc
This commit is contained in:
commit
51087d2247
917 changed files with 22996 additions and 25543 deletions
41
Cargo.lock
41
Cargo.lock
|
@ -524,7 +524,7 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
|||
|
||||
[[package]]
|
||||
name = "clippy"
|
||||
version = "0.1.82"
|
||||
version = "0.1.83"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"cargo_metadata 0.18.1",
|
||||
|
@ -547,13 +547,13 @@ dependencies = [
|
|||
"termize",
|
||||
"tokio",
|
||||
"toml 0.7.8",
|
||||
"ui_test 0.25.0",
|
||||
"ui_test",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clippy_config"
|
||||
version = "0.1.82"
|
||||
version = "0.1.83"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"serde",
|
||||
|
@ -576,7 +576,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.82"
|
||||
version = "0.1.83"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"cargo_metadata 0.18.1",
|
||||
|
@ -600,7 +600,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clippy_utils"
|
||||
version = "0.1.82"
|
||||
version = "0.1.83"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"clippy_config",
|
||||
|
@ -902,7 +902,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "declare_clippy_lint"
|
||||
version = "0.1.82"
|
||||
version = "0.1.83"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"quote",
|
||||
|
@ -2269,7 +2269,7 @@ dependencies = [
|
|||
"rustc_version",
|
||||
"smallvec",
|
||||
"tempfile",
|
||||
"ui_test 0.26.5",
|
||||
"ui_test",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
|
@ -5485,33 +5485,6 @@ version = "0.1.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
||||
|
||||
[[package]]
|
||||
name = "ui_test"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7e4f339f62edc873975c47115f9e71c5454ddaa37c1142b42fc0b2672c8dacb"
|
||||
dependencies = [
|
||||
"annotate-snippets 0.11.4",
|
||||
"anyhow",
|
||||
"bstr",
|
||||
"cargo-platform",
|
||||
"cargo_metadata 0.18.1",
|
||||
"color-eyre",
|
||||
"colored",
|
||||
"comma",
|
||||
"crossbeam-channel",
|
||||
"indicatif",
|
||||
"lazy_static",
|
||||
"levenshtein",
|
||||
"prettydiff",
|
||||
"regex",
|
||||
"rustc_version",
|
||||
"rustfix",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"spanned",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ui_test"
|
||||
version = "0.26.5"
|
||||
|
|
|
@ -4,9 +4,9 @@ use rustc_ast::{NodeId, PatKind, attr, token};
|
|||
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, Features, GateIssue};
|
||||
use rustc_session::Session;
|
||||
use rustc_session::parse::{feature_err, feature_err_issue, feature_warn};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::spec::abi;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
|
@ -483,6 +483,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
|||
pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||
maybe_stage_features(sess, features, krate);
|
||||
check_incompatible_features(sess, features);
|
||||
check_new_solver_banned_features(sess, features);
|
||||
|
||||
let mut visitor = PostExpansionVisitor { sess, features };
|
||||
|
||||
let spans = sess.psess.gated_spans.spans.borrow();
|
||||
|
@ -662,3 +664,22 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_new_solver_banned_features(sess: &Session, features: &Features) {
|
||||
if !sess.opts.unstable_opts.next_solver.is_some_and(|n| n.globally) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ban GCE with the new solver, because it does not implement GCE correctly.
|
||||
if let Some(&(_, gce_span, _)) = features
|
||||
.declared_lang_features
|
||||
.iter()
|
||||
.find(|&&(feat, _, _)| feat == sym::generic_const_exprs)
|
||||
{
|
||||
sess.dcx().emit_err(errors::IncompatibleFeatures {
|
||||
spans: vec![gce_span],
|
||||
f1: Symbol::intern("-Znext-solver=globally"),
|
||||
f2: sym::generic_const_exprs,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::error::Error;
|
||||
use std::fmt::Debug;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
use polonius_engine::{AllFacts as PoloniusFacts, Atom};
|
||||
|
@ -127,7 +127,7 @@ impl<'w> FactWriter<'w> {
|
|||
T: FactRow,
|
||||
{
|
||||
let file = &self.dir.join(file_name);
|
||||
let mut file = BufWriter::new(File::create(file)?);
|
||||
let mut file = File::create_buffered(file)?;
|
||||
for row in rows {
|
||||
row.write(&mut file, self.location_table)?;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(control_flow_enum)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(never_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
|
|
@ -34,7 +34,22 @@ pub(crate) fn unsized_info<'tcx>(
|
|||
let old_info =
|
||||
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
|
||||
if data_a.principal_def_id() == data_b.principal_def_id() {
|
||||
// A NOP cast that doesn't actually change anything, should be allowed even with invalid vtables.
|
||||
// Codegen takes advantage of the additional assumption, where if the
|
||||
// principal trait def id of what's being casted doesn't change,
|
||||
// then we don't need to adjust the vtable at all. This
|
||||
// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
|
||||
// requires that `A = B`; we don't allow *upcasting* objects
|
||||
// between the same trait with different args. If we, for
|
||||
// some reason, were to relax the `Unsize` trait, it could become
|
||||
// unsound, so let's assert here that the trait refs are *equal*.
|
||||
//
|
||||
// We can use `assert_eq` because the binders should have been anonymized,
|
||||
// and because higher-ranked equality now requires the binders are equal.
|
||||
debug_assert_eq!(
|
||||
data_a.principal(),
|
||||
data_b.principal(),
|
||||
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
|
||||
);
|
||||
return old_info;
|
||||
}
|
||||
|
||||
|
|
|
@ -808,8 +808,7 @@ struct ThinLTOKeysMap {
|
|||
impl ThinLTOKeysMap {
|
||||
fn save_to_file(&self, path: &Path) -> io::Result<()> {
|
||||
use std::io::Write;
|
||||
let file = File::create(path)?;
|
||||
let mut writer = io::BufWriter::new(file);
|
||||
let mut writer = File::create_buffered(path)?;
|
||||
// The entries are loaded back into a hash map in `load_from_file()`, so
|
||||
// the order in which we write them to file here does not matter.
|
||||
for (module, key) in &self.keys {
|
||||
|
@ -821,8 +820,8 @@ impl ThinLTOKeysMap {
|
|||
fn load_from_file(path: &Path) -> io::Result<Self> {
|
||||
use std::io::BufRead;
|
||||
let mut keys = BTreeMap::default();
|
||||
let file = File::open(path)?;
|
||||
for line in io::BufReader::new(file).lines() {
|
||||
let file = File::open_buffered(path)?;
|
||||
for line in file.lines() {
|
||||
let line = line?;
|
||||
let mut split = line.split(' ');
|
||||
let module = split.next().unwrap();
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#![feature(assert_matches)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(hash_raw_entry)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(iter_intersperse)]
|
||||
|
|
|
@ -1087,16 +1087,17 @@ fn link_natively(
|
|||
let strip = sess.opts.cg.strip;
|
||||
|
||||
if sess.target.is_like_osx {
|
||||
let stripcmd = "/usr/bin/strip";
|
||||
match (strip, crate_type) {
|
||||
(Strip::Debuginfo, _) => {
|
||||
strip_symbols_with_external_utility(sess, "strip", out_filename, Some("-S"))
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-S"))
|
||||
}
|
||||
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
|
||||
(Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
|
||||
strip_symbols_with_external_utility(sess, "strip", out_filename, Some("-x"))
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, Some("-x"))
|
||||
}
|
||||
(Strip::Symbols, _) => {
|
||||
strip_symbols_with_external_utility(sess, "strip", out_filename, None)
|
||||
strip_symbols_with_external_utility(sess, stripcmd, out_filename, None)
|
||||
}
|
||||
(Strip::None, _) => {}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use std::ffi::{OsStr, OsString};
|
||||
use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
use std::io::{self, BufWriter};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{env, iter, mem, str};
|
||||
use std::{env, io, iter, mem, str};
|
||||
|
||||
use cc::windows_registry;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
|
@ -754,7 +753,7 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
if self.sess.target.is_like_osx {
|
||||
// Write a plain, newline-separated list of symbols
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = BufWriter::new(File::create(&path)?);
|
||||
let mut f = File::create_buffered(&path)?;
|
||||
for sym in symbols {
|
||||
debug!(" _{sym}");
|
||||
writeln!(f, "_{sym}")?;
|
||||
|
@ -765,7 +764,7 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
}
|
||||
} else if is_windows {
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = BufWriter::new(File::create(&path)?);
|
||||
let mut f = File::create_buffered(&path)?;
|
||||
|
||||
// .def file similar to MSVC one but without LIBRARY section
|
||||
// because LD doesn't like when it's empty
|
||||
|
@ -781,7 +780,7 @@ impl<'a> Linker for GccLinker<'a> {
|
|||
} else {
|
||||
// Write an LD version script
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = BufWriter::new(File::create(&path)?);
|
||||
let mut f = File::create_buffered(&path)?;
|
||||
writeln!(f, "{{")?;
|
||||
if !symbols.is_empty() {
|
||||
writeln!(f, " global:")?;
|
||||
|
@ -1059,7 +1058,7 @@ impl<'a> Linker for MsvcLinker<'a> {
|
|||
|
||||
let path = tmpdir.join("lib.def");
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = BufWriter::new(File::create(&path)?);
|
||||
let mut f = File::create_buffered(&path)?;
|
||||
|
||||
// Start off with the standard module name header and then go
|
||||
// straight to exports.
|
||||
|
@ -1648,7 +1647,7 @@ impl<'a> Linker for AixLinker<'a> {
|
|||
fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
|
||||
let path = tmpdir.join("list.exp");
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = BufWriter::new(File::create(&path)?);
|
||||
let mut f = File::create_buffered(&path)?;
|
||||
// FIXME: use llvm-nm to generate export list.
|
||||
for symbol in symbols {
|
||||
debug!(" _{symbol}");
|
||||
|
@ -1961,7 +1960,7 @@ impl<'a> Linker for BpfLinker<'a> {
|
|||
fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
|
||||
let path = tmpdir.join("symbols");
|
||||
let res: io::Result<()> = try {
|
||||
let mut f = BufWriter::new(File::create(&path)?);
|
||||
let mut f = File::create_buffered(&path)?;
|
||||
for sym in symbols {
|
||||
writeln!(f, "{sym}")?;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ use crate::back::write::{
|
|||
submit_codegened_module_to_llvm, submit_post_lto_module_to_llvm, submit_pre_lto_module_to_llvm,
|
||||
};
|
||||
use crate::common::{self, IntPredicate, RealPredicate, TypeKind};
|
||||
use crate::meth::load_vtable;
|
||||
use crate::mir::operand::OperandValue;
|
||||
use crate::mir::place::PlaceRef;
|
||||
use crate::traits::*;
|
||||
|
@ -124,8 +125,28 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
let old_info =
|
||||
old_info.expect("unsized_info: missing old info for trait upcasting coercion");
|
||||
if data_a.principal_def_id() == data_b.principal_def_id() {
|
||||
// A NOP cast that doesn't actually change anything, should be allowed even with
|
||||
// invalid vtables.
|
||||
// Codegen takes advantage of the additional assumption, where if the
|
||||
// principal trait def id of what's being casted doesn't change,
|
||||
// then we don't need to adjust the vtable at all. This
|
||||
// corresponds to the fact that `dyn Tr<A>: Unsize<dyn Tr<B>>`
|
||||
// requires that `A = B`; we don't allow *upcasting* objects
|
||||
// between the same trait with different args. If we, for
|
||||
// some reason, were to relax the `Unsize` trait, it could become
|
||||
// unsound, so let's assert here that the trait refs are *equal*.
|
||||
//
|
||||
// We can use `assert_eq` because the binders should have been anonymized,
|
||||
// and because higher-ranked equality now requires the binders are equal.
|
||||
debug_assert_eq!(
|
||||
data_a.principal(),
|
||||
data_b.principal(),
|
||||
"NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}"
|
||||
);
|
||||
|
||||
// A NOP cast that doesn't actually change anything, let's avoid any
|
||||
// unnecessary work. This relies on the assumption that if the principal
|
||||
// traits are equal, then the associated type bounds (`dyn Trait<Assoc=T>`)
|
||||
// are also equal, which is ensured by the fact that normalization is
|
||||
// a function and we do not allow overlapping impls.
|
||||
return old_info;
|
||||
}
|
||||
|
||||
|
@ -135,14 +156,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
|
||||
if let Some(entry_idx) = vptr_entry_idx {
|
||||
let ptr_size = bx.data_layout().pointer_size;
|
||||
let ptr_align = bx.data_layout().pointer_align.abi;
|
||||
let vtable_byte_offset = u64::try_from(entry_idx).unwrap() * ptr_size.bytes();
|
||||
let gep = bx.inbounds_ptradd(old_info, bx.const_usize(vtable_byte_offset));
|
||||
let new_vptr = bx.load(bx.type_ptr(), gep, ptr_align);
|
||||
bx.nonnull_metadata(new_vptr);
|
||||
// VTable loads are invariant.
|
||||
bx.set_invariant_load(new_vptr);
|
||||
new_vptr
|
||||
load_vtable(bx, old_info, bx.type_ptr(), vtable_byte_offset, source, true)
|
||||
} else {
|
||||
old_info
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#![doc(rust_logo)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(negative_impls)]
|
||||
|
|
|
@ -28,27 +28,9 @@ impl<'a, 'tcx> VirtualIndex {
|
|||
|
||||
let llty = bx.fn_ptr_backend_type(fn_abi);
|
||||
let ptr_size = bx.data_layout().pointer_size;
|
||||
let ptr_align = bx.data_layout().pointer_align.abi;
|
||||
let vtable_byte_offset = self.0 * ptr_size.bytes();
|
||||
|
||||
if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
|
||||
&& bx.cx().sess().lto() == Lto::Fat
|
||||
{
|
||||
let typeid = bx
|
||||
.typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty)))
|
||||
.unwrap();
|
||||
let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
|
||||
func
|
||||
} else {
|
||||
let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset));
|
||||
let ptr = bx.load(llty, gep, ptr_align);
|
||||
// VTable loads are invariant.
|
||||
bx.set_invariant_load(ptr);
|
||||
if nonnull {
|
||||
bx.nonnull_metadata(ptr);
|
||||
}
|
||||
ptr
|
||||
}
|
||||
load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, nonnull)
|
||||
}
|
||||
|
||||
pub(crate) fn get_optional_fn<Bx: BuilderMethods<'a, 'tcx>>(
|
||||
|
@ -75,31 +57,27 @@ impl<'a, 'tcx> VirtualIndex {
|
|||
self,
|
||||
bx: &mut Bx,
|
||||
llvtable: Bx::Value,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Bx::Value {
|
||||
// Load the data pointer from the object.
|
||||
debug!("get_int({:?}, {:?})", llvtable, self);
|
||||
|
||||
let llty = bx.type_isize();
|
||||
let ptr_size = bx.data_layout().pointer_size;
|
||||
let ptr_align = bx.data_layout().pointer_align.abi;
|
||||
let vtable_byte_offset = self.0 * ptr_size.bytes();
|
||||
|
||||
let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset));
|
||||
let ptr = bx.load(llty, gep, ptr_align);
|
||||
// VTable loads are invariant.
|
||||
bx.set_invariant_load(ptr);
|
||||
ptr
|
||||
load_vtable(bx, llvtable, llty, vtable_byte_offset, ty, false)
|
||||
}
|
||||
}
|
||||
|
||||
/// This takes a valid `self` receiver type and extracts the principal trait
|
||||
/// ref of the type.
|
||||
fn expect_dyn_trait_in_self(ty: Ty<'_>) -> ty::PolyExistentialTraitRef<'_> {
|
||||
/// ref of the type. Return `None` if there is no principal trait.
|
||||
fn dyn_trait_in_self(ty: Ty<'_>) -> Option<ty::PolyExistentialTraitRef<'_>> {
|
||||
for arg in ty.peel_refs().walk() {
|
||||
if let GenericArgKind::Type(ty) = arg.unpack()
|
||||
&& let ty::Dynamic(data, _, _) = ty.kind()
|
||||
{
|
||||
return data.principal().expect("expected principal trait object");
|
||||
return data.principal();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,3 +116,36 @@ pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>(
|
|||
cx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
|
||||
vtable
|
||||
}
|
||||
|
||||
/// Call this function whenever you need to load a vtable.
|
||||
pub(crate) fn load_vtable<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
||||
bx: &mut Bx,
|
||||
llvtable: Bx::Value,
|
||||
llty: Bx::Type,
|
||||
vtable_byte_offset: u64,
|
||||
ty: Ty<'tcx>,
|
||||
nonnull: bool,
|
||||
) -> Bx::Value {
|
||||
let ptr_align = bx.data_layout().pointer_align.abi;
|
||||
|
||||
if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
|
||||
&& bx.cx().sess().lto() == Lto::Fat
|
||||
{
|
||||
if let Some(trait_ref) = dyn_trait_in_self(ty) {
|
||||
let typeid = bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), trait_ref)).unwrap();
|
||||
let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
|
||||
return func;
|
||||
} else if nonnull {
|
||||
bug!("load nonnull value from a vtable without a principal trait")
|
||||
}
|
||||
}
|
||||
|
||||
let gep = bx.inbounds_ptradd(llvtable, bx.const_usize(vtable_byte_offset));
|
||||
let ptr = bx.load(llty, gep, ptr_align);
|
||||
// VTable loads are invariant.
|
||||
bx.set_invariant_load(ptr);
|
||||
if nonnull {
|
||||
bx.nonnull_metadata(ptr);
|
||||
}
|
||||
ptr
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::collections::hash_map::Entry;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Range;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
@ -14,7 +15,7 @@ use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx};
|
|||
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
use super::place::{PlaceRef, PlaceValue};
|
||||
use super::{FunctionCx, LocalRef};
|
||||
use super::{FunctionCx, LocalRef, PerLocalVarDebugInfoIndexVec};
|
||||
use crate::traits::*;
|
||||
|
||||
pub struct FunctionDebugContext<'tcx, S, L> {
|
||||
|
@ -48,6 +49,17 @@ pub struct PerLocalVarDebugInfo<'tcx, D> {
|
|||
pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
|
||||
}
|
||||
|
||||
/// Information needed to emit a constant.
|
||||
pub struct ConstDebugInfo<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
||||
pub name: String,
|
||||
pub source_info: mir::SourceInfo,
|
||||
pub operand: OperandRef<'tcx, Bx::Value>,
|
||||
pub dbg_var: Bx::DIVariable,
|
||||
pub dbg_loc: Bx::DILocation,
|
||||
pub fragment: Option<Range<Size>>,
|
||||
pub _phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct DebugScope<S, L> {
|
||||
pub dbg_scope: S,
|
||||
|
@ -427,11 +439,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn debug_introduce_locals(&self, bx: &mut Bx) {
|
||||
pub(crate) fn debug_introduce_locals(
|
||||
&self,
|
||||
bx: &mut Bx,
|
||||
consts: Vec<ConstDebugInfo<'a, 'tcx, Bx>>,
|
||||
) {
|
||||
if bx.sess().opts.debuginfo == DebugInfo::Full || !bx.sess().fewer_names() {
|
||||
for local in self.locals.indices() {
|
||||
self.debug_introduce_local(bx, local);
|
||||
}
|
||||
|
||||
for ConstDebugInfo { name, source_info, operand, dbg_var, dbg_loc, fragment, .. } in
|
||||
consts.into_iter()
|
||||
{
|
||||
self.set_debug_loc(bx, source_info);
|
||||
let base = FunctionCx::spill_operand_to_stack(operand, Some(name), bx);
|
||||
bx.clear_dbg_loc();
|
||||
|
||||
bx.dbg_var_addr(dbg_var, dbg_loc, base.val.llval, Size::ZERO, &[], fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -439,7 +465,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
pub(crate) fn compute_per_local_var_debug_info(
|
||||
&self,
|
||||
bx: &mut Bx,
|
||||
) -> Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>> {
|
||||
) -> Option<(
|
||||
PerLocalVarDebugInfoIndexVec<'tcx, Bx::DIVariable>,
|
||||
Vec<ConstDebugInfo<'a, 'tcx, Bx>>,
|
||||
)> {
|
||||
let full_debug_info = self.cx.sess().opts.debuginfo == DebugInfo::Full;
|
||||
|
||||
let target_is_msvc = self.cx.sess().target.is_like_msvc;
|
||||
|
@ -449,6 +478,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
}
|
||||
|
||||
let mut per_local = IndexVec::from_elem(vec![], &self.mir.local_decls);
|
||||
let mut constants = vec![];
|
||||
let mut params_seen: FxHashMap<_, Bx::DIVariable> = Default::default();
|
||||
for var in &self.mir.var_debug_info {
|
||||
let dbg_scope_and_span = if full_debug_info {
|
||||
|
@ -545,23 +575,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
|
||||
|
||||
let operand = self.eval_mir_constant_to_operand(bx, &c);
|
||||
self.set_debug_loc(bx, var.source_info);
|
||||
let base =
|
||||
Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx);
|
||||
bx.clear_dbg_loc();
|
||||
|
||||
bx.dbg_var_addr(
|
||||
constants.push(ConstDebugInfo {
|
||||
name: var.name.to_string(),
|
||||
source_info: var.source_info,
|
||||
operand,
|
||||
dbg_var,
|
||||
dbg_loc,
|
||||
base.val.llval,
|
||||
Size::ZERO,
|
||||
&[],
|
||||
fragment,
|
||||
);
|
||||
_phantom: PhantomData,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(per_local)
|
||||
Some((per_local, constants))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN,
|
||||
_ => bug!(),
|
||||
};
|
||||
let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable);
|
||||
let value = meth::VirtualIndex::from_index(idx).get_usize(bx, vtable, callee_ty);
|
||||
match name {
|
||||
// Size is always <= isize::MAX.
|
||||
sym::vtable_size => {
|
||||
|
|
|
@ -41,6 +41,9 @@ enum CachedLlbb<T> {
|
|||
Skip,
|
||||
}
|
||||
|
||||
type PerLocalVarDebugInfoIndexVec<'tcx, V> =
|
||||
IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, V>>>;
|
||||
|
||||
/// Master context for codegenning from MIR.
|
||||
pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
||||
instance: Instance<'tcx>,
|
||||
|
@ -107,8 +110,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
|
|||
|
||||
/// All `VarDebugInfo` from the MIR body, partitioned by `Local`.
|
||||
/// This is `None` if no variable debuginfo/names are needed.
|
||||
per_local_var_debug_info:
|
||||
Option<IndexVec<mir::Local, Vec<PerLocalVarDebugInfo<'tcx, Bx::DIVariable>>>>,
|
||||
per_local_var_debug_info: Option<PerLocalVarDebugInfoIndexVec<'tcx, Bx::DIVariable>>,
|
||||
|
||||
/// Caller location propagated if this function has `#[track_caller]`.
|
||||
caller_location: Option<OperandRef<'tcx, Bx::Value>>,
|
||||
|
@ -216,7 +218,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// monomorphization, and if there is an error during collection then codegen never starts -- so
|
||||
// we don't have to do it again.
|
||||
|
||||
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
|
||||
let (per_local_var_debug_info, consts_debug_info) =
|
||||
fx.compute_per_local_var_debug_info(&mut start_bx).unzip();
|
||||
fx.per_local_var_debug_info = per_local_var_debug_info;
|
||||
|
||||
let traversal_order = traversal::mono_reachable_reverse_postorder(mir, cx.tcx(), instance);
|
||||
let memory_locals = analyze::non_ssa_locals(&fx, &traversal_order);
|
||||
|
@ -268,7 +272,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
fx.initialize_locals(local_values);
|
||||
|
||||
// Apply debuginfo to the newly allocated locals.
|
||||
fx.debug_introduce_locals(&mut start_bx);
|
||||
fx.debug_introduce_locals(&mut start_bx, consts_debug_info.unwrap_or_default());
|
||||
|
||||
// If the backend supports coverage, and coverage is enabled for this function,
|
||||
// do any necessary start-of-function codegen (e.g. locals for MC/DC bitmaps).
|
||||
|
|
|
@ -28,9 +28,9 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||
// Load size/align from vtable.
|
||||
let vtable = info.unwrap();
|
||||
let size = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_SIZE)
|
||||
.get_usize(bx, vtable);
|
||||
.get_usize(bx, vtable, t);
|
||||
let align = meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_ALIGN)
|
||||
.get_usize(bx, vtable);
|
||||
.get_usize(bx, vtable, t);
|
||||
|
||||
// Size is always <= isize::MAX.
|
||||
let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#![feature(cfg_match)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(extend_one)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(hash_raw_entry)]
|
||||
#![feature(macro_metavar_expr)]
|
||||
#![feature(map_try_insert)]
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::env::var_os;
|
||||
use std::fs::File;
|
||||
use std::io::BufWriter;
|
||||
use std::path::Path;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
|
@ -33,7 +32,7 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||
|
||||
let file_path = dir.as_ref().join(format!("{counter:010}_{description}.gv"));
|
||||
|
||||
let mut gv_file = BufWriter::new(File::create(file_path).unwrap());
|
||||
let mut gv_file = File::create_buffered(file_path).unwrap();
|
||||
|
||||
dot::render(&self, &mut gv_file).unwrap();
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::util;
|
||||
use rustc_middle::ty::fold::shift_vars;
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||
self, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::Span;
|
||||
|
@ -42,14 +43,18 @@ fn associated_type_bounds<'tcx>(
|
|||
let trait_def_id = tcx.local_parent(assoc_item_def_id);
|
||||
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
|
||||
|
||||
let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
|
||||
match pred.kind().skip_binder() {
|
||||
ty::ClauseKind::Trait(tr) => tr.self_ty() == item_ty,
|
||||
ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty() == item_ty,
|
||||
ty::ClauseKind::TypeOutlives(outlives) => outlives.0 == item_ty,
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
let item_trait_ref = ty::TraitRef::identity(tcx, tcx.parent(assoc_item_def_id.to_def_id()));
|
||||
let bounds_from_parent =
|
||||
trait_predicates.predicates.iter().copied().filter_map(|(clause, span)| {
|
||||
remap_gat_vars_and_recurse_into_nested_projections(
|
||||
tcx,
|
||||
filter,
|
||||
item_trait_ref,
|
||||
assoc_item_def_id,
|
||||
span,
|
||||
clause,
|
||||
)
|
||||
});
|
||||
|
||||
let all_bounds = tcx.arena.alloc_from_iter(bounds.clauses(tcx).chain(bounds_from_parent));
|
||||
debug!(
|
||||
|
@ -63,6 +68,226 @@ fn associated_type_bounds<'tcx>(
|
|||
all_bounds
|
||||
}
|
||||
|
||||
/// The code below is quite involved, so let me explain.
|
||||
///
|
||||
/// We loop here, because we also want to collect vars for nested associated items as
|
||||
/// well. For example, given a clause like `Self::A::B`, we want to add that to the
|
||||
/// item bounds for `A`, so that we may use that bound in the case that `Self::A::B` is
|
||||
/// rigid.
|
||||
///
|
||||
/// Secondly, regarding bound vars, when we see a where clause that mentions a GAT
|
||||
/// like `for<'a, ...> Self::Assoc<'a, ...>: Bound<'b, ...>`, we want to turn that into
|
||||
/// an item bound on the GAT, where all of the GAT args are substituted with the GAT's
|
||||
/// param regions, and then keep all of the other late-bound vars in the bound around.
|
||||
/// We need to "compress" the binder so that it doesn't mention any of those vars that
|
||||
/// were mapped to params.
|
||||
fn remap_gat_vars_and_recurse_into_nested_projections<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
filter: PredicateFilter,
|
||||
item_trait_ref: ty::TraitRef<'tcx>,
|
||||
assoc_item_def_id: LocalDefId,
|
||||
span: Span,
|
||||
clause: ty::Clause<'tcx>,
|
||||
) -> Option<(ty::Clause<'tcx>, Span)> {
|
||||
let mut clause_ty = match clause.kind().skip_binder() {
|
||||
ty::ClauseKind::Trait(tr) => tr.self_ty(),
|
||||
ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty(),
|
||||
ty::ClauseKind::TypeOutlives(outlives) => outlives.0,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let gat_vars = loop {
|
||||
if let ty::Alias(ty::Projection, alias_ty) = *clause_ty.kind() {
|
||||
if alias_ty.trait_ref(tcx) == item_trait_ref
|
||||
&& alias_ty.def_id == assoc_item_def_id.to_def_id()
|
||||
{
|
||||
// We have found the GAT in question...
|
||||
// Return the vars, since we may need to remap them.
|
||||
break &alias_ty.args[item_trait_ref.args.len()..];
|
||||
} else {
|
||||
// Only collect *self* type bounds if the filter is for self.
|
||||
match filter {
|
||||
PredicateFilter::SelfOnly | PredicateFilter::SelfThatDefines(_) => {
|
||||
return None;
|
||||
}
|
||||
PredicateFilter::All | PredicateFilter::SelfAndAssociatedTypeBounds => {}
|
||||
}
|
||||
|
||||
clause_ty = alias_ty.self_ty();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
};
|
||||
|
||||
// Special-case: No GAT vars, no mapping needed.
|
||||
if gat_vars.is_empty() {
|
||||
return Some((clause, span));
|
||||
}
|
||||
|
||||
// First, check that all of the GAT args are substituted with a unique late-bound arg.
|
||||
// If we find a duplicate, then it can't be mapped to the definition's params.
|
||||
let mut mapping = FxIndexMap::default();
|
||||
let generics = tcx.generics_of(assoc_item_def_id);
|
||||
for (param, var) in std::iter::zip(&generics.own_params, gat_vars) {
|
||||
let existing = match var.unpack() {
|
||||
ty::GenericArgKind::Lifetime(re) => {
|
||||
if let ty::RegionKind::ReBound(ty::INNERMOST, bv) = re.kind() {
|
||||
mapping.insert(bv.var, tcx.mk_param_from_def(param))
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
if let ty::Bound(ty::INNERMOST, bv) = *ty.kind() {
|
||||
mapping.insert(bv.var, tcx.mk_param_from_def(param))
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
ty::GenericArgKind::Const(ct) => {
|
||||
if let ty::ConstKind::Bound(ty::INNERMOST, bv) = ct.kind() {
|
||||
mapping.insert(bv, tcx.mk_param_from_def(param))
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if existing.is_some() {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, map all of the args in the GAT to the params we expect, and compress
|
||||
// the remaining late-bound vars so that they count up from var 0.
|
||||
let mut folder =
|
||||
MapAndCompressBoundVars { tcx, binder: ty::INNERMOST, still_bound_vars: vec![], mapping };
|
||||
let pred = clause.kind().skip_binder().fold_with(&mut folder);
|
||||
|
||||
Some((
|
||||
ty::Binder::bind_with_vars(pred, tcx.mk_bound_variable_kinds(&folder.still_bound_vars))
|
||||
.upcast(tcx),
|
||||
span,
|
||||
))
|
||||
}
|
||||
|
||||
/// Given some where clause like `for<'b, 'c> <Self as Trait<'a_identity>>::Gat<'b>: Bound<'c>`,
|
||||
/// the mapping will map `'b` back to the GAT's `'b_identity`. Then we need to compress the
|
||||
/// remaining bound var `'c` to index 0.
|
||||
///
|
||||
/// This folder gives us: `for<'c> <Self as Trait<'a_identity>>::Gat<'b_identity>: Bound<'c>`,
|
||||
/// which is sufficient for an item bound for `Gat`, since all of the GAT's args are identity.
|
||||
struct MapAndCompressBoundVars<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
/// How deep are we? Makes sure we don't touch the vars of nested binders.
|
||||
binder: ty::DebruijnIndex,
|
||||
/// List of bound vars that remain unsubstituted because they were not
|
||||
/// mentioned in the GAT's args.
|
||||
still_bound_vars: Vec<ty::BoundVariableKind>,
|
||||
/// Subtle invariant: If the `GenericArg` is bound, then it should be
|
||||
/// stored with the debruijn index of `INNERMOST` so it can be shifted
|
||||
/// correctly during substitution.
|
||||
mapping: FxIndexMap<ty::BoundVar, ty::GenericArg<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for MapAndCompressBoundVars<'tcx> {
|
||||
fn cx(&self) -> TyCtxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
|
||||
where
|
||||
ty::Binder<'tcx, T>: TypeSuperFoldable<TyCtxt<'tcx>>,
|
||||
{
|
||||
self.binder.shift_in(1);
|
||||
let out = t.super_fold_with(self);
|
||||
self.binder.shift_out(1);
|
||||
out
|
||||
}
|
||||
|
||||
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
|
||||
if !ty.has_bound_vars() {
|
||||
return ty;
|
||||
}
|
||||
|
||||
if let ty::Bound(binder, old_bound) = *ty.kind()
|
||||
&& self.binder == binder
|
||||
{
|
||||
let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) {
|
||||
mapped.expect_ty()
|
||||
} else {
|
||||
// If we didn't find a mapped generic, then make a new one.
|
||||
// Allocate a new var idx, and insert a new bound ty.
|
||||
let var = ty::BoundVar::from_usize(self.still_bound_vars.len());
|
||||
self.still_bound_vars.push(ty::BoundVariableKind::Ty(old_bound.kind));
|
||||
let mapped = Ty::new_bound(self.tcx, ty::INNERMOST, ty::BoundTy {
|
||||
var,
|
||||
kind: old_bound.kind,
|
||||
});
|
||||
self.mapping.insert(old_bound.var, mapped.into());
|
||||
mapped
|
||||
};
|
||||
|
||||
shift_vars(self.tcx, mapped, self.binder.as_u32())
|
||||
} else {
|
||||
ty.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_region(&mut self, re: ty::Region<'tcx>) -> ty::Region<'tcx> {
|
||||
if let ty::ReBound(binder, old_bound) = re.kind()
|
||||
&& self.binder == binder
|
||||
{
|
||||
let mapped = if let Some(mapped) = self.mapping.get(&old_bound.var) {
|
||||
mapped.expect_region()
|
||||
} else {
|
||||
let var = ty::BoundVar::from_usize(self.still_bound_vars.len());
|
||||
self.still_bound_vars.push(ty::BoundVariableKind::Region(old_bound.kind));
|
||||
let mapped = ty::Region::new_bound(self.tcx, ty::INNERMOST, ty::BoundRegion {
|
||||
var,
|
||||
kind: old_bound.kind,
|
||||
});
|
||||
self.mapping.insert(old_bound.var, mapped.into());
|
||||
mapped
|
||||
};
|
||||
|
||||
shift_vars(self.tcx, mapped, self.binder.as_u32())
|
||||
} else {
|
||||
re
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
|
||||
if !ct.has_bound_vars() {
|
||||
return ct;
|
||||
}
|
||||
|
||||
if let ty::ConstKind::Bound(binder, old_var) = ct.kind()
|
||||
&& self.binder == binder
|
||||
{
|
||||
let mapped = if let Some(mapped) = self.mapping.get(&old_var) {
|
||||
mapped.expect_const()
|
||||
} else {
|
||||
let var = ty::BoundVar::from_usize(self.still_bound_vars.len());
|
||||
self.still_bound_vars.push(ty::BoundVariableKind::Const);
|
||||
let mapped = ty::Const::new_bound(self.tcx, ty::INNERMOST, var);
|
||||
self.mapping.insert(old_var, mapped.into());
|
||||
mapped
|
||||
};
|
||||
|
||||
shift_vars(self.tcx, mapped, self.binder.as_u32())
|
||||
} else {
|
||||
ct.super_fold_with(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
||||
if !p.has_bound_vars() { p } else { p.super_fold_with(self) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Opaque types don't inherit bounds from their parent: for return position
|
||||
/// impl trait it isn't possible to write a suitable predicate on the
|
||||
/// containing function and for type-alias impl trait we don't have a backwards
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
use std::env;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::io::Write;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_data_structures::graph::implementation::{Direction, INCOMING, NodeIndex, OUTGOING};
|
||||
|
@ -245,7 +245,7 @@ fn dump_graph(query: &DepGraphQuery) {
|
|||
{
|
||||
// dump a .txt file with just the edges:
|
||||
let txt_path = format!("{path}.txt");
|
||||
let mut file = BufWriter::new(File::create(&txt_path).unwrap());
|
||||
let mut file = File::create_buffered(&txt_path).unwrap();
|
||||
for (source, target) in &edges {
|
||||
write!(file, "{source:?} -> {target:?}\n").unwrap();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#![deny(missing_docs)]
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![warn(unreachable_pub)]
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// tidy-alphabetical-start
|
||||
#![feature(decl_macro)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(try_blocks)]
|
||||
#![warn(unreachable_pub)]
|
||||
|
|
|
@ -519,7 +519,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
|||
write_deps_to_file(&mut file)?;
|
||||
}
|
||||
OutFileName::Real(ref path) => {
|
||||
let mut file = BufWriter::new(fs::File::create(path)?);
|
||||
let mut file = fs::File::create_buffered(path)?;
|
||||
write_deps_to_file(&mut file)?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,8 +128,7 @@ pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> {
|
|||
}
|
||||
|
||||
pub fn copy_to_stdout(from: &Path) -> io::Result<()> {
|
||||
let file = fs::File::open(from)?;
|
||||
let mut reader = io::BufReader::new(file);
|
||||
let mut reader = fs::File::open_buffered(from)?;
|
||||
let mut stdout = io::stdout();
|
||||
io::copy(&mut reader, &mut stdout)?;
|
||||
Ok(())
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#![feature(decl_macro)]
|
||||
#![feature(error_iter)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(iter_from_coroutine)]
|
||||
#![feature(let_chains)]
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#![feature(discriminant_kind)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(extract_if)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(intra_doc_pointers)]
|
||||
#![feature(iter_from_coroutine)]
|
||||
|
|
|
@ -277,9 +277,9 @@ pub fn create_dump_file<'tcx>(
|
|||
)
|
||||
})?;
|
||||
}
|
||||
Ok(io::BufWriter::new(fs::File::create(&file_path).map_err(|e| {
|
||||
Ok(fs::File::create_buffered(&file_path).map_err(|e| {
|
||||
io::Error::new(e.kind(), format!("IO error creating MIR dump file: {file_path:?}; {e}"))
|
||||
})?))
|
||||
})?)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -266,7 +266,7 @@ where
|
|||
A::Domain: DebugWithContext<A>,
|
||||
{
|
||||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::io::Write;
|
||||
|
||||
let def_id = body.source.def_id();
|
||||
let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else {
|
||||
|
@ -281,8 +281,7 @@ where
|
|||
if let Some(parent) = path.parent() {
|
||||
fs::create_dir_all(parent)?;
|
||||
}
|
||||
let f = fs::File::create(&path)?;
|
||||
io::BufWriter::new(f)
|
||||
fs::File::create_buffered(&path)?
|
||||
}
|
||||
|
||||
None if dump_enabled(tcx, A::NAME, def_id) => {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#![feature(associated_type_defaults)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(try_blocks)]
|
||||
#![warn(unreachable_pub)]
|
||||
|
|
|
@ -24,7 +24,7 @@ pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> {
|
|||
write_mir_pretty(tcx, None, &mut f)?;
|
||||
}
|
||||
OutFileName::Real(path) => {
|
||||
let mut f = io::BufWriter::new(File::create(&path)?);
|
||||
let mut f = File::create_buffered(&path)?;
|
||||
write_mir_pretty(tcx, None, &mut f)?;
|
||||
if tcx.sess.opts.json_artifact_notifications {
|
||||
tcx.dcx().emit_artifact_notification(&path, "mir");
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#![feature(box_patterns)]
|
||||
#![feature(const_type_name)]
|
||||
#![feature(cow_is_borrowed)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(let_chains)]
|
||||
|
|
|
@ -4,7 +4,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
|||
use rustc_hir::LangItem;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_infer::traits::Reveal;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::{Obligation, ObligationCause, Reveal};
|
||||
use rustc_middle::mir::coverage::CoverageKind;
|
||||
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
|
@ -16,6 +17,8 @@ use rustc_middle::ty::{
|
|||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_target::abi::{FIRST_VARIANT, Size};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
use rustc_type_ir::Upcast;
|
||||
|
||||
use crate::util::{is_within_packed, relate_types};
|
||||
|
||||
|
@ -586,6 +589,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||
|
||||
crate::util::relate_types(self.tcx, self.param_env, variance, src, dest)
|
||||
}
|
||||
|
||||
/// Check that the given predicate definitely holds in the param-env of this MIR body.
|
||||
fn predicate_must_hold_modulo_regions(
|
||||
&self,
|
||||
pred: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
|
||||
) -> bool {
|
||||
let infcx = self.tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
ocx.register_obligation(Obligation::new(
|
||||
self.tcx,
|
||||
ObligationCause::dummy(),
|
||||
self.param_env,
|
||||
pred,
|
||||
));
|
||||
ocx.select_all_or_error().is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
|
@ -1202,8 +1221,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
CastKind::PointerCoercion(PointerCoercion::Unsize, _) => {
|
||||
// This is used for all `CoerceUnsized` types,
|
||||
// not just pointers/references, so is hard to check.
|
||||
// Pointers being unsize coerced should at least implement
|
||||
// `CoerceUnsized`.
|
||||
if !self.predicate_must_hold_modulo_regions(ty::TraitRef::new(
|
||||
self.tcx,
|
||||
self.tcx.require_lang_item(
|
||||
LangItem::CoerceUnsized,
|
||||
Some(self.body.source_info(location).span),
|
||||
),
|
||||
[op_ty, *target_type],
|
||||
)) {
|
||||
self.fail(location, format!("Unsize coercion, but `{op_ty}` isn't coercible to `{target_type}`"));
|
||||
}
|
||||
}
|
||||
CastKind::PointerCoercion(PointerCoercion::DynStar, _) => {
|
||||
// FIXME(dyn-star): make sure nothing needs to be done here.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// tidy-alphabetical-start
|
||||
#![feature(array_windows)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(let_chains)]
|
||||
#![warn(unreachable_pub)]
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
use std::cmp;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::fs::{self, File};
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
|
@ -1243,8 +1243,7 @@ fn dump_mono_items_stats<'tcx>(
|
|||
let ext = format.extension();
|
||||
let filename = format!("{crate_name}.mono_items.{ext}");
|
||||
let output_path = output_directory.join(&filename);
|
||||
let file = File::create(&output_path)?;
|
||||
let mut file = BufWriter::new(file);
|
||||
let mut file = File::create_buffered(&output_path)?;
|
||||
|
||||
// Gather instantiated mono items grouped by def_id
|
||||
let mut items_per_def_id: FxIndexMap<_, Vec<_>> = Default::default();
|
||||
|
|
|
@ -1840,6 +1840,8 @@ supported_targets! {
|
|||
("powerpc-wrs-vxworks", powerpc_wrs_vxworks),
|
||||
("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe),
|
||||
("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks),
|
||||
("riscv32-wrs-vxworks", riscv32_wrs_vxworks),
|
||||
("riscv64-wrs-vxworks", riscv64_wrs_vxworks),
|
||||
|
||||
("aarch64-kmc-solid_asp3", aarch64_kmc_solid_asp3),
|
||||
("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi),
|
||||
|
|
|
@ -5,8 +5,7 @@ pub(crate) fn target() -> Target {
|
|||
base.max_atomic_width = Some(128);
|
||||
|
||||
Target {
|
||||
// LLVM 15 doesn't support OpenHarmony yet, use a linux target instead.
|
||||
llvm_target: "aarch64-unknown-linux-musl".into(),
|
||||
llvm_target: "aarch64-unknown-linux-ohos".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("ARM64 OpenHarmony".into()),
|
||||
tier: Some(2),
|
||||
|
|
|
@ -7,7 +7,7 @@ pub(crate) fn target() -> Target {
|
|||
description: None,
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
|
||||
|
|
|
@ -7,8 +7,7 @@ pub(crate) fn target() -> Target {
|
|||
// Most of these settings are copied from the armv7_unknown_linux_musleabi
|
||||
// target.
|
||||
Target {
|
||||
// LLVM 15 doesn't support OpenHarmony yet, use a linux target instead.
|
||||
llvm_target: "armv7-unknown-linux-gnueabi".into(),
|
||||
llvm_target: "armv7-unknown-linux-ohos".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("Armv7-A OpenHarmony".into()),
|
||||
tier: Some(2),
|
||||
|
|
|
@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
|
|||
description: None,
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
|
||||
|
|
|
@ -2,8 +2,7 @@ use crate::spec::{Target, TargetOptions, base};
|
|||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
// LLVM 15 doesn't support OpenHarmony yet, use a linux target instead.
|
||||
llvm_target: "loongarch64-unknown-linux-musl".into(),
|
||||
llvm_target: "loongarch64-unknown-linux-ohos".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("LoongArch64 OpenHarmony".into()),
|
||||
tier: Some(3),
|
||||
|
|
|
@ -14,7 +14,7 @@ pub(crate) fn target() -> Target {
|
|||
description: None,
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(),
|
||||
|
|
|
@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
|
|||
description: None,
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(),
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
use crate::spec::{StackProbeType, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
llvm_target: "riscv32".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: None,
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 32,
|
||||
data_layout: "e-m:e-p:32:32-i64:64-n32-S128".into(),
|
||||
arch: "riscv32".into(),
|
||||
options: TargetOptions {
|
||||
cpu: "generic-rv32".into(),
|
||||
llvm_abiname: "ilp32d".into(),
|
||||
max_atomic_width: Some(32),
|
||||
features: "+m,+a,+f,+d,+c".into(),
|
||||
stack_probes: StackProbeType::Inline,
|
||||
..base::vxworks::opts()
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
use crate::spec::{StackProbeType, Target, TargetOptions, base};
|
||||
|
||||
pub(crate) fn target() -> Target {
|
||||
Target {
|
||||
llvm_target: "riscv64".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: None,
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
|
||||
arch: "riscv64".into(),
|
||||
options: TargetOptions {
|
||||
cpu: "generic-rv64".into(),
|
||||
llvm_abiname: "lp64d".into(),
|
||||
max_atomic_width: Some(64),
|
||||
features: "+m,+a,+f,+d,+c".into(),
|
||||
stack_probes: StackProbeType::Inline,
|
||||
..base::vxworks::opts()
|
||||
},
|
||||
}
|
||||
}
|
|
@ -15,8 +15,7 @@ pub(crate) fn target() -> Target {
|
|||
base.supports_xray = true;
|
||||
|
||||
Target {
|
||||
// LLVM 15 doesn't support OpenHarmony yet, use a linux target instead.
|
||||
llvm_target: "x86_64-unknown-linux-musl".into(),
|
||||
llvm_target: "x86_64-unknown-linux-ohos".into(),
|
||||
metadata: crate::spec::TargetMetadata {
|
||||
description: Some("x86_64 OpenHarmony".into()),
|
||||
tier: Some(2),
|
||||
|
|
|
@ -15,7 +15,7 @@ pub(crate) fn target() -> Target {
|
|||
description: None,
|
||||
tier: Some(3),
|
||||
host_tools: Some(false),
|
||||
std: None, // ?
|
||||
std: Some(true),
|
||||
},
|
||||
pointer_width: 64,
|
||||
data_layout:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#![cfg_attr(feature = "optimize_for_size", allow(dead_code))]
|
||||
#![cfg_attr(any(feature = "optimize_for_size", target_pointer_width = "16"), allow(dead_code))]
|
||||
|
||||
use crate::marker::Freeze;
|
||||
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
//! This module contains the entry points for `slice::sort`.
|
||||
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
|
||||
use crate::cmp;
|
||||
use crate::intrinsics;
|
||||
use crate::mem::{self, MaybeUninit, SizedTypeProperties};
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
|
||||
use crate::slice::sort::shared::smallsort::{
|
||||
SMALL_SORT_GENERAL_SCRATCH_LEN, StableSmallSortTypeImpl, insertion_sort_shift_left,
|
||||
};
|
||||
|
||||
pub(crate) mod merge;
|
||||
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
|
||||
pub(crate) mod drift;
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
|
||||
pub(crate) mod quicksort;
|
||||
|
||||
#[cfg(feature = "optimize_for_size")]
|
||||
#[cfg(any(feature = "optimize_for_size", target_pointer_width = "16"))]
|
||||
pub(crate) mod tiny;
|
||||
|
||||
/// Stable sort called driftsort by Orson Peters and Lukas Bergdoll.
|
||||
|
@ -45,7 +45,7 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less
|
|||
|
||||
cfg_if! {
|
||||
if #[cfg(target_pointer_width = "16")] {
|
||||
let heap_buf = BufT::with_capacity(alloc_len);
|
||||
let mut heap_buf = BufT::with_capacity(alloc_len);
|
||||
let scratch = heap_buf.as_uninit_slice_mut();
|
||||
} else {
|
||||
// For small inputs 4KiB of stack storage suffices, which allows us to avoid
|
||||
|
@ -85,7 +85,7 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less
|
|||
///
|
||||
/// Deliberately don't inline the main sorting routine entrypoint to ensure the
|
||||
/// inlined insertion sort i-cache footprint remains minimal.
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
|
||||
#[inline(never)]
|
||||
fn driftsort_main<T, F: FnMut(&T, &T) -> bool, BufT: BufGuard<T>>(v: &mut [T], is_less: &mut F) {
|
||||
// By allocating n elements of memory we can ensure the entire input can
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
use crate::intrinsics;
|
||||
use crate::mem::SizedTypeProperties;
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
|
||||
use crate::slice::sort::shared::find_existing_run;
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
|
||||
use crate::slice::sort::shared::smallsort::insertion_sort_shift_left;
|
||||
|
||||
pub(crate) mod heapsort;
|
||||
|
@ -55,7 +55,7 @@ pub fn sort<T, F: FnMut(&T, &T) -> bool>(v: &mut [T], is_less: &mut F) {
|
|||
///
|
||||
/// Deliberately don't inline the main sorting routine entrypoint to ensure the
|
||||
/// inlined insertion sort i-cache footprint remains minimal.
|
||||
#[cfg(not(feature = "optimize_for_size"))]
|
||||
#[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))]
|
||||
#[inline(never)]
|
||||
fn ipnsort<T, F>(v: &mut [T], is_less: &mut F)
|
||||
where
|
||||
|
|
|
@ -48,7 +48,7 @@ cfg_if::cfg_if! {
|
|||
target_os = "psp",
|
||||
target_os = "xous",
|
||||
target_os = "solid_asp3",
|
||||
all(target_family = "unix", not(any(target_os = "espidf", target_os = "rtems"))),
|
||||
all(target_family = "unix", not(any(target_os = "espidf", target_os = "rtems", target_os = "nuttx"))),
|
||||
all(target_vendor = "fortanix", target_env = "sgx"),
|
||||
target_family = "wasm",
|
||||
))] {
|
||||
|
|
|
@ -54,6 +54,7 @@ fn main() {
|
|||
|| target_os == "teeos"
|
||||
|| target_os == "zkvm"
|
||||
|| target_os == "rtems"
|
||||
|| target_os == "nuttx"
|
||||
|
||||
// See src/bootstrap/src/core/build_steps/synthetic_targets.rs
|
||||
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
|
||||
|
|
|
@ -375,6 +375,44 @@ impl File {
|
|||
OpenOptions::new().read(true).open(path.as_ref())
|
||||
}
|
||||
|
||||
/// Attempts to open a file in read-only mode with buffering.
|
||||
///
|
||||
/// See the [`OpenOptions::open`] method, the [`BufReader`][io::BufReader] type,
|
||||
/// and the [`BufRead`][io::BufRead] trait for more details.
|
||||
///
|
||||
/// If you only need to read the entire file contents,
|
||||
/// consider [`std::fs::read()`][self::read] or
|
||||
/// [`std::fs::read_to_string()`][self::read_to_string] instead.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error if `path` does not already exist.
|
||||
/// Other errors may also be returned according to [`OpenOptions::open`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(file_buffered)]
|
||||
/// use std::fs::File;
|
||||
/// use std::io::BufRead;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let mut f = File::open_buffered("foo.txt")?;
|
||||
/// assert!(f.capacity() > 0);
|
||||
/// for (line, i) in f.lines().zip(1..) {
|
||||
/// println!("{i:6}: {}", line?);
|
||||
/// }
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "file_buffered", issue = "130804")]
|
||||
pub fn open_buffered<P: AsRef<Path>>(path: P) -> io::Result<io::BufReader<File>> {
|
||||
// Allocate the buffer *first* so we don't affect the filesystem otherwise.
|
||||
let buffer = io::BufReader::<Self>::try_new_buffer()?;
|
||||
let file = File::open(path)?;
|
||||
Ok(io::BufReader::with_buffer(file, buffer))
|
||||
}
|
||||
|
||||
/// Opens a file in write-only mode.
|
||||
///
|
||||
/// This function will create a file if it does not exist,
|
||||
|
@ -404,6 +442,45 @@ impl File {
|
|||
OpenOptions::new().write(true).create(true).truncate(true).open(path.as_ref())
|
||||
}
|
||||
|
||||
/// Opens a file in write-only mode with buffering.
|
||||
///
|
||||
/// This function will create a file if it does not exist,
|
||||
/// and will truncate it if it does.
|
||||
///
|
||||
/// Depending on the platform, this function may fail if the
|
||||
/// full directory path does not exist.
|
||||
///
|
||||
/// See the [`OpenOptions::open`] method and the
|
||||
/// [`BufWriter`][io::BufWriter] type for more details.
|
||||
///
|
||||
/// See also [`std::fs::write()`][self::write] for a simple function to
|
||||
/// create a file with some given data.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(file_buffered)]
|
||||
/// use std::fs::File;
|
||||
/// use std::io::Write;
|
||||
///
|
||||
/// fn main() -> std::io::Result<()> {
|
||||
/// let mut f = File::create_buffered("foo.txt")?;
|
||||
/// assert!(f.capacity() > 0);
|
||||
/// for i in 0..100 {
|
||||
/// writeln!(&mut f, "{i}")?;
|
||||
/// }
|
||||
/// f.flush()?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "file_buffered", issue = "130804")]
|
||||
pub fn create_buffered<P: AsRef<Path>>(path: P) -> io::Result<io::BufWriter<File>> {
|
||||
// Allocate the buffer *first* so we don't affect the filesystem otherwise.
|
||||
let buffer = io::BufWriter::<Self>::try_new_buffer()?;
|
||||
let file = File::create(path)?;
|
||||
Ok(io::BufWriter::with_buffer(file, buffer))
|
||||
}
|
||||
|
||||
/// Creates a new file in read-write mode; error if the file exists.
|
||||
///
|
||||
/// This function will create a file if it does not exist, or return an error if it does. This
|
||||
|
|
|
@ -74,6 +74,14 @@ impl<R: Read> BufReader<R> {
|
|||
BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
|
||||
}
|
||||
|
||||
pub(crate) fn try_new_buffer() -> io::Result<Buffer> {
|
||||
Buffer::try_with_capacity(DEFAULT_BUF_SIZE)
|
||||
}
|
||||
|
||||
pub(crate) fn with_buffer(inner: R, buf: Buffer) -> Self {
|
||||
Self { inner, buf }
|
||||
}
|
||||
|
||||
/// Creates a new `BufReader<R>` with the specified buffer capacity.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//! without encountering any runtime bounds checks.
|
||||
|
||||
use crate::cmp;
|
||||
use crate::io::{self, BorrowedBuf, Read};
|
||||
use crate::io::{self, BorrowedBuf, ErrorKind, Read};
|
||||
use crate::mem::MaybeUninit;
|
||||
|
||||
pub struct Buffer {
|
||||
|
@ -36,6 +36,16 @@ impl Buffer {
|
|||
Self { buf, pos: 0, filled: 0, initialized: 0 }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_with_capacity(capacity: usize) -> io::Result<Self> {
|
||||
match Box::try_new_uninit_slice(capacity) {
|
||||
Ok(buf) => Ok(Self { buf, pos: 0, filled: 0, initialized: 0 }),
|
||||
Err(_) => {
|
||||
Err(io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate read buffer"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
// SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and
|
||||
|
|
|
@ -94,6 +94,16 @@ impl<W: Write> BufWriter<W> {
|
|||
BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
|
||||
}
|
||||
|
||||
pub(crate) fn try_new_buffer() -> io::Result<Vec<u8>> {
|
||||
Vec::try_with_capacity(DEFAULT_BUF_SIZE).map_err(|_| {
|
||||
io::const_io_error!(ErrorKind::OutOfMemory, "failed to allocate write buffer")
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn with_buffer(inner: W, buf: Vec<u8>) -> Self {
|
||||
Self { inner, buf, panicked: false }
|
||||
}
|
||||
|
||||
/// Creates a new `BufWriter<W>` with at least the specified buffer capacity.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
@ -402,7 +402,7 @@ pub enum ErrorKind {
|
|||
|
||||
/// The operation was partially successful and needs to be checked
|
||||
/// later on due to not blocking.
|
||||
#[unstable(feature = "io_error_inprogress", issue = "none")]
|
||||
#[unstable(feature = "io_error_inprogress", issue = "130840")]
|
||||
InProgress,
|
||||
|
||||
// "Unusual" error kinds which do not correspond simply to (sets
|
||||
|
|
|
@ -374,6 +374,7 @@
|
|||
#![feature(slice_concat_trait)]
|
||||
#![feature(thin_box)]
|
||||
#![feature(try_reserve_kind)]
|
||||
#![feature(try_with_capacity)]
|
||||
#![feature(vec_into_raw_parts)]
|
||||
// tidy-alphabetical-end
|
||||
//
|
||||
|
|
|
@ -139,6 +139,8 @@ pub mod macos;
|
|||
pub mod netbsd;
|
||||
#[cfg(target_os = "nto")]
|
||||
pub mod nto;
|
||||
#[cfg(target_os = "nuttx")]
|
||||
pub mod nuttx;
|
||||
#[cfg(target_os = "openbsd")]
|
||||
pub mod openbsd;
|
||||
#[cfg(target_os = "redox")]
|
||||
|
|
92
library/std/src/os/nuttx/fs.rs
Normal file
92
library/std/src/os/nuttx/fs.rs
Normal file
|
@ -0,0 +1,92 @@
|
|||
#![stable(feature = "metadata_ext", since = "1.1.0")]
|
||||
|
||||
use crate::fs::Metadata;
|
||||
use crate::sys_common::AsInner;
|
||||
|
||||
#[stable(feature = "metadata_ext", since = "1.1.0")]
|
||||
pub trait MetadataExt {
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_dev(&self) -> u64;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_ino(&self) -> u64;
|
||||
#[stable(feature = "metadata_ext", since = "1.1.0")]
|
||||
fn st_mode(&self) -> u32;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_nlink(&self) -> u64;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_uid(&self) -> u32;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_gid(&self) -> u32;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_rdev(&self) -> u64;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_size(&self) -> u64;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_atime(&self) -> i64;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_atime_nsec(&self) -> i64;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_mtime(&self) -> i64;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_mtime_nsec(&self) -> i64;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_ctime(&self) -> i64;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_ctime_nsec(&self) -> i64;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_blksize(&self) -> u64;
|
||||
#[stable(feature = "metadata_ext2", since = "1.8.0")]
|
||||
fn st_blocks(&self) -> u64;
|
||||
}
|
||||
|
||||
#[stable(feature = "metadata_ext", since = "1.1.0")]
|
||||
impl MetadataExt for Metadata {
|
||||
fn st_dev(&self) -> u64 {
|
||||
self.as_inner().as_inner().st_dev as u64
|
||||
}
|
||||
fn st_ino(&self) -> u64 {
|
||||
self.as_inner().as_inner().st_ino as u64
|
||||
}
|
||||
fn st_mode(&self) -> u32 {
|
||||
self.as_inner().as_inner().st_mode as u32
|
||||
}
|
||||
fn st_nlink(&self) -> u64 {
|
||||
self.as_inner().as_inner().st_nlink as u64
|
||||
}
|
||||
fn st_uid(&self) -> u32 {
|
||||
self.as_inner().as_inner().st_uid as u32
|
||||
}
|
||||
fn st_gid(&self) -> u32 {
|
||||
self.as_inner().as_inner().st_gid as u32
|
||||
}
|
||||
fn st_rdev(&self) -> u64 {
|
||||
self.as_inner().as_inner().st_rdev as u64
|
||||
}
|
||||
fn st_size(&self) -> u64 {
|
||||
self.as_inner().as_inner().st_size as u64
|
||||
}
|
||||
fn st_atime(&self) -> i64 {
|
||||
self.as_inner().as_inner().st_atim.tv_sec as i64
|
||||
}
|
||||
fn st_atime_nsec(&self) -> i64 {
|
||||
self.as_inner().as_inner().st_atim.tv_nsec as i64
|
||||
}
|
||||
fn st_mtime(&self) -> i64 {
|
||||
self.as_inner().as_inner().st_mtim.tv_sec as i64
|
||||
}
|
||||
fn st_mtime_nsec(&self) -> i64 {
|
||||
self.as_inner().as_inner().st_mtim.tv_nsec as i64
|
||||
}
|
||||
fn st_ctime(&self) -> i64 {
|
||||
self.as_inner().as_inner().st_ctim.tv_sec as i64
|
||||
}
|
||||
fn st_ctime_nsec(&self) -> i64 {
|
||||
self.as_inner().as_inner().st_ctim.tv_nsec as i64
|
||||
}
|
||||
fn st_blksize(&self) -> u64 {
|
||||
self.as_inner().as_inner().st_blksize as u64
|
||||
}
|
||||
fn st_blocks(&self) -> u64 {
|
||||
self.as_inner().as_inner().st_blocks as u64
|
||||
}
|
||||
}
|
4
library/std/src/os/nuttx/mod.rs
Normal file
4
library/std/src/os/nuttx/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
#![stable(feature = "raw_ext", since = "1.1.0")]
|
||||
#![forbid(unsafe_op_in_unsafe_fn)]
|
||||
pub mod fs;
|
||||
pub(crate) mod raw;
|
33
library/std/src/os/nuttx/raw.rs
Normal file
33
library/std/src/os/nuttx/raw.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
//! rtems raw type definitions
|
||||
|
||||
#![stable(feature = "raw_ext", since = "1.1.0")]
|
||||
#![deprecated(
|
||||
since = "1.8.0",
|
||||
note = "these type aliases are no longer supported by \
|
||||
the standard library, the `libc` crate on \
|
||||
crates.io should be used instead for the correct \
|
||||
definitions"
|
||||
)]
|
||||
#![allow(deprecated)]
|
||||
|
||||
#[stable(feature = "pthread_t", since = "1.8.0")]
|
||||
pub type pthread_t = libc::pthread_t;
|
||||
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type blkcnt_t = libc::blkcnt_t;
|
||||
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type blksize_t = libc::blksize_t;
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type dev_t = libc::dev_t;
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type ino_t = libc::ino_t;
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type mode_t = libc::mode_t;
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type nlink_t = libc::nlink_t;
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type off_t = libc::off_t;
|
||||
|
||||
#[stable(feature = "raw_ext", since = "1.1.0")]
|
||||
pub type time_t = libc::time_t;
|
|
@ -69,6 +69,8 @@ mod platform {
|
|||
pub use crate::os::netbsd::*;
|
||||
#[cfg(target_os = "nto")]
|
||||
pub use crate::os::nto::*;
|
||||
#[cfg(target_os = "nuttx")]
|
||||
pub use crate::os::nuttx::*;
|
||||
#[cfg(target_os = "openbsd")]
|
||||
pub use crate::os::openbsd::*;
|
||||
#[cfg(target_os = "redox")]
|
||||
|
|
|
@ -71,7 +71,8 @@ impl RandomSource for DefaultRandomSource {
|
|||
///
|
||||
/// This is a convenience function for `T::random(&mut DefaultRandomSource)` and
|
||||
/// will sample according to the same distribution as the underlying [`Random`]
|
||||
/// trait implementation.
|
||||
/// trait implementation. See [`DefaultRandomSource`] for more information about
|
||||
/// how randomness is sourced.
|
||||
///
|
||||
/// **Warning:** Be careful when manipulating random values! The
|
||||
/// [`random`](Random::random) method on integers samples them with a uniform
|
||||
|
|
|
@ -71,6 +71,7 @@ cfg_if::cfg_if! {
|
|||
}
|
||||
} else {
|
||||
#[inline]
|
||||
#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
|
||||
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
|
||||
let mut out = ptr::null_mut();
|
||||
// We prefer posix_memalign over aligned_alloc since it is more widely available, and
|
||||
|
|
|
@ -105,84 +105,7 @@ mod os {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod os {
|
||||
use super::DebuggerPresence;
|
||||
use crate::fs::File;
|
||||
use crate::io::Read;
|
||||
|
||||
pub(super) fn is_debugger_present() -> Option<DebuggerPresence> {
|
||||
// This function is crafted with the following goals:
|
||||
// * Memory efficiency: It avoids crashing the panicking process due to
|
||||
// out-of-memory (OOM) conditions by not using large heap buffers or
|
||||
// allocating significant stack space, which could lead to stack overflow.
|
||||
// * Minimal binary size: The function uses a minimal set of facilities
|
||||
// from the standard library to avoid increasing the resulting binary size.
|
||||
//
|
||||
// To achieve these goals, the function does not use `[std::io::BufReader]`
|
||||
// and instead reads the file byte by byte using a sliding window approach.
|
||||
// It's important to note that the "/proc/self/status" pseudo-file is synthesized
|
||||
// by the Virtual File System (VFS), meaning it is not read from a slow or
|
||||
// non-volatile storage medium so buffering might not be as beneficial because
|
||||
// all data is read from memory, though this approach does incur a syscall for
|
||||
// each byte read.
|
||||
//
|
||||
// We cannot make assumptions about the file size or the position of the
|
||||
// target prefix ("TracerPid:"), so the function does not use
|
||||
// `[std::fs::read_to_string]` thus not employing UTF-8 to ASCII checking,
|
||||
// conversion, or parsing as we're looking for an ASCII prefix.
|
||||
//
|
||||
// These condiderations make the function deviate from the familiar concise pattern
|
||||
// of searching for a string in a text file.
|
||||
|
||||
fn read_byte(file: &mut File) -> Option<u8> {
|
||||
let mut buffer = [0];
|
||||
file.read_exact(&mut buffer).ok()?;
|
||||
Some(buffer[0])
|
||||
}
|
||||
|
||||
// The ASCII prefix of the datum we're interested in.
|
||||
const TRACER_PID: &[u8] = b"TracerPid:\t";
|
||||
|
||||
let mut file = File::open("/proc/self/status").ok()?;
|
||||
let mut matched = 0;
|
||||
|
||||
// Look for the `TRACER_PID` prefix.
|
||||
while let Some(byte) = read_byte(&mut file) {
|
||||
if byte == TRACER_PID[matched] {
|
||||
matched += 1;
|
||||
if matched == TRACER_PID.len() {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
matched = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Was the prefix found?
|
||||
if matched != TRACER_PID.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// It was; get the ASCII representation of the first digit
|
||||
// of the PID. That is enough to see if there is a debugger
|
||||
// attached as the kernel does not pad the PID on the left
|
||||
// with the leading zeroes.
|
||||
let byte = read_byte(&mut file)?;
|
||||
if byte.is_ascii_digit() && byte != b'0' {
|
||||
Some(DebuggerPresence::Detected)
|
||||
} else {
|
||||
Some(DebuggerPresence::NotDetected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "windows",
|
||||
target_vendor = "apple",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux"
|
||||
)))]
|
||||
#[cfg(not(any(target_os = "windows", target_vendor = "apple", target_os = "freebsd")))]
|
||||
mod os {
|
||||
pub(super) fn is_debugger_present() -> Option<super::DebuggerPresence> {
|
||||
None
|
||||
|
|
|
@ -113,6 +113,7 @@ impl DoubleEndedIterator for Args {
|
|||
target_os = "nto",
|
||||
target_os = "hurd",
|
||||
target_os = "rtems",
|
||||
target_os = "nuttx",
|
||||
))]
|
||||
mod imp {
|
||||
use crate::ffi::c_char;
|
||||
|
|
|
@ -283,3 +283,14 @@ pub mod os {
|
|||
pub const EXE_SUFFIX: &str = "";
|
||||
pub const EXE_EXTENSION: &str = "";
|
||||
}
|
||||
|
||||
#[cfg(target_os = "nuttx")]
|
||||
pub mod os {
|
||||
pub const FAMILY: &str = "unix";
|
||||
pub const OS: &str = "nuttx";
|
||||
pub const DLL_PREFIX: &str = "lib";
|
||||
pub const DLL_SUFFIX: &str = ".so";
|
||||
pub const DLL_EXTENSION: &str = "so";
|
||||
pub const EXE_SUFFIX: &str = "";
|
||||
pub const EXE_EXTENSION: &str = "";
|
||||
}
|
||||
|
|
|
@ -98,7 +98,12 @@ impl FileDesc {
|
|||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))]
|
||||
#[cfg(not(any(
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vita",
|
||||
target_os = "nuttx"
|
||||
)))]
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
let ret = cvt(unsafe {
|
||||
libc::readv(
|
||||
|
@ -110,14 +115,24 @@ impl FileDesc {
|
|||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
|
||||
#[cfg(any(
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vita",
|
||||
target_os = "nuttx"
|
||||
))]
|
||||
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
|
||||
io::default_read_vectored(|b| self.read(b), bufs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_read_vectored(&self) -> bool {
|
||||
cfg!(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))
|
||||
cfg!(not(any(
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vita",
|
||||
target_os = "nuttx"
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||
|
@ -297,7 +312,12 @@ impl FileDesc {
|
|||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))]
|
||||
#[cfg(not(any(
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vita",
|
||||
target_os = "nuttx"
|
||||
)))]
|
||||
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
let ret = cvt(unsafe {
|
||||
libc::writev(
|
||||
|
@ -309,14 +329,24 @@ impl FileDesc {
|
|||
Ok(ret as usize)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
|
||||
#[cfg(any(
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vita",
|
||||
target_os = "nuttx"
|
||||
))]
|
||||
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
|
||||
io::default_write_vectored(|b| self.write(b), bufs)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_write_vectored(&self) -> bool {
|
||||
cfg!(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))
|
||||
cfg!(not(any(
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vita",
|
||||
target_os = "nuttx"
|
||||
)))
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
|
||||
|
|
|
@ -479,6 +479,7 @@ impl FileAttr {
|
|||
target_os = "vita",
|
||||
target_os = "hurd",
|
||||
target_os = "rtems",
|
||||
target_os = "nuttx",
|
||||
)))]
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
|
@ -501,7 +502,7 @@ impl FileAttr {
|
|||
SystemTime::new(self.stat.st_mtime as i64, 0)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "horizon", target_os = "hurd"))]
|
||||
#[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))]
|
||||
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||
SystemTime::new(self.stat.st_mtim.tv_sec as i64, self.stat.st_mtim.tv_nsec as i64)
|
||||
}
|
||||
|
@ -513,6 +514,7 @@ impl FileAttr {
|
|||
target_os = "vita",
|
||||
target_os = "hurd",
|
||||
target_os = "rtems",
|
||||
target_os = "nuttx",
|
||||
)))]
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
|
@ -535,7 +537,7 @@ impl FileAttr {
|
|||
SystemTime::new(self.stat.st_atime as i64, 0)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "horizon", target_os = "hurd"))]
|
||||
#[cfg(any(target_os = "horizon", target_os = "hurd", target_os = "nuttx"))]
|
||||
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||
SystemTime::new(self.stat.st_atim.tv_sec as i64, self.stat.st_atim.tv_nsec as i64)
|
||||
}
|
||||
|
@ -866,6 +868,7 @@ impl Drop for Dir {
|
|||
target_os = "horizon",
|
||||
target_os = "vxworks",
|
||||
target_os = "rtems",
|
||||
target_os = "nuttx",
|
||||
)))]
|
||||
{
|
||||
let fd = unsafe { libc::dirfd(self.0) };
|
||||
|
@ -1000,6 +1003,13 @@ impl DirEntry {
|
|||
self.entry.d_fileno as u64
|
||||
}
|
||||
|
||||
#[cfg(target_os = "nuttx")]
|
||||
pub fn ino(&self) -> u64 {
|
||||
// Leave this 0 for now, as NuttX does not provide an inode number
|
||||
// in its directory entries.
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(any(
|
||||
target_os = "netbsd",
|
||||
target_os = "openbsd",
|
||||
|
@ -1327,7 +1337,8 @@ impl File {
|
|||
target_os = "redox",
|
||||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vxworks"
|
||||
target_os = "vxworks",
|
||||
target_os = "nuttx",
|
||||
)))]
|
||||
let to_timespec = |time: Option<SystemTime>| match time {
|
||||
Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts),
|
||||
|
@ -1342,7 +1353,7 @@ impl File {
|
|||
None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
|
||||
};
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks"))] {
|
||||
if #[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "vxworks", target_os = "nuttx"))] {
|
||||
// Redox doesn't appear to support `UTIME_OMIT`.
|
||||
// ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore
|
||||
// the same as for Redox.
|
||||
|
|
|
@ -222,6 +222,7 @@ static ON_BROKEN_PIPE_FLAG_USED: crate::sync::atomic::AtomicBool =
|
|||
target_os = "horizon",
|
||||
target_os = "vxworks",
|
||||
target_os = "vita",
|
||||
target_os = "nuttx",
|
||||
)))]
|
||||
pub(crate) fn on_broken_pipe_flag_used() -> bool {
|
||||
ON_BROKEN_PIPE_FLAG_USED.load(crate::sync::atomic::Ordering::Relaxed)
|
||||
|
@ -425,7 +426,7 @@ cfg_if::cfg_if! {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
|
||||
#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))]
|
||||
mod unsupported {
|
||||
use crate::io;
|
||||
|
||||
|
|
|
@ -38,19 +38,19 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
|
|||
// We may need to trigger a glibc workaround. See on_resolver_failure() for details.
|
||||
on_resolver_failure();
|
||||
|
||||
#[cfg(not(target_os = "espidf"))]
|
||||
#[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
|
||||
if err == libc::EAI_SYSTEM {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "espidf"))]
|
||||
#[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
|
||||
let detail = unsafe {
|
||||
// We can't always expect a UTF-8 environment. When we don't get that luxury,
|
||||
// it's better to give a low-quality error message than none at all.
|
||||
CStr::from_ptr(libc::gai_strerror(err)).to_string_lossy()
|
||||
};
|
||||
|
||||
#[cfg(target_os = "espidf")]
|
||||
#[cfg(any(target_os = "espidf", target_os = "nuttx"))]
|
||||
let detail = "";
|
||||
|
||||
Err(io::Error::new(
|
||||
|
|
|
@ -48,6 +48,7 @@ extern "C" {
|
|||
target_os = "openbsd",
|
||||
target_os = "android",
|
||||
target_os = "redox",
|
||||
target_os = "nuttx",
|
||||
target_env = "newlib"
|
||||
),
|
||||
link_name = "__errno"
|
||||
|
@ -399,6 +400,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
|
|||
target_os = "linux",
|
||||
target_os = "hurd",
|
||||
target_os = "android",
|
||||
target_os = "nuttx",
|
||||
target_os = "emscripten"
|
||||
))]
|
||||
pub fn current_exe() -> io::Result<PathBuf> {
|
||||
|
@ -717,6 +719,7 @@ pub fn home_dir() -> Option<PathBuf> {
|
|||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vita",
|
||||
target_os = "nuttx",
|
||||
all(target_vendor = "apple", not(target_os = "macos")),
|
||||
))]
|
||||
unsafe fn fallback() -> Option<OsString> {
|
||||
|
@ -730,6 +733,7 @@ pub fn home_dir() -> Option<PathBuf> {
|
|||
target_os = "espidf",
|
||||
target_os = "horizon",
|
||||
target_os = "vita",
|
||||
target_os = "nuttx",
|
||||
all(target_vendor = "apple", not(target_os = "macos")),
|
||||
)))]
|
||||
unsafe fn fallback() -> Option<OsString> {
|
||||
|
|
|
@ -2,10 +2,10 @@ pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes
|
|||
pub use self::process_inner::{ExitStatus, ExitStatusError, Process};
|
||||
pub use crate::ffi::OsString as EnvKey;
|
||||
|
||||
#[cfg_attr(any(target_os = "espidf", target_os = "horizon"), allow(unused))]
|
||||
#[cfg_attr(any(target_os = "espidf", target_os = "horizon", target_os = "nuttx"), allow(unused))]
|
||||
mod process_common;
|
||||
|
||||
#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))]
|
||||
#[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))]
|
||||
mod process_unsupported;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
|
@ -16,7 +16,7 @@ cfg_if::cfg_if! {
|
|||
} else if #[cfg(target_os = "vxworks")] {
|
||||
#[path = "process_vxworks.rs"]
|
||||
mod process_inner;
|
||||
} else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita"))] {
|
||||
} else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] {
|
||||
mod process_inner {
|
||||
pub use super::process_unsupported::*;
|
||||
}
|
||||
|
|
|
@ -140,7 +140,12 @@ impl Thread {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
|
||||
#[cfg(any(
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd",
|
||||
target_os = "nuttx"
|
||||
))]
|
||||
pub fn set_name(name: &CStr) {
|
||||
unsafe {
|
||||
libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
|
||||
|
@ -517,7 +522,7 @@ mod cgroups {
|
|||
use crate::borrow::Cow;
|
||||
use crate::ffi::OsString;
|
||||
use crate::fs::{File, exists};
|
||||
use crate::io::{BufRead, BufReader, Read};
|
||||
use crate::io::{BufRead, Read};
|
||||
use crate::os::unix::ffi::OsStringExt;
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::str::from_utf8;
|
||||
|
@ -690,7 +695,7 @@ mod cgroups {
|
|||
/// If the cgroupfs is a bind mount then `group_path` is adjusted to skip
|
||||
/// over the already-included prefix
|
||||
fn find_mountpoint(group_path: &Path) -> Option<(Cow<'static, str>, &Path)> {
|
||||
let mut reader = BufReader::new(File::open("/proc/self/mountinfo").ok()?);
|
||||
let mut reader = File::open_buffered("/proc/self/mountinfo").ok()?;
|
||||
let mut line = String::with_capacity(256);
|
||||
loop {
|
||||
line.clear();
|
||||
|
@ -747,12 +752,15 @@ unsafe fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
|
|||
}
|
||||
|
||||
// No point in looking up __pthread_get_minstack() on non-glibc platforms.
|
||||
#[cfg(all(not(all(target_os = "linux", target_env = "gnu")), not(target_os = "netbsd")))]
|
||||
#[cfg(all(
|
||||
not(all(target_os = "linux", target_env = "gnu")),
|
||||
not(any(target_os = "netbsd", target_os = "nuttx"))
|
||||
))]
|
||||
unsafe fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
|
||||
libc::PTHREAD_STACK_MIN
|
||||
}
|
||||
|
||||
#[cfg(target_os = "netbsd")]
|
||||
#[cfg(any(target_os = "netbsd", target_os = "nuttx"))]
|
||||
unsafe fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
|
||||
static STACK: crate::sync::OnceLock<usize> = crate::sync::OnceLock::new();
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ cfg_if::cfg_if! {
|
|||
target_os = "psp",
|
||||
target_os = "xous",
|
||||
target_os = "solid_asp3",
|
||||
all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "rtems")),
|
||||
all(target_family = "unix", not(target_os = "espidf"), not(target_os = "l4re"), not(target_os = "rtems"), not(target_os = "nuttx")),
|
||||
all(target_vendor = "fortanix", target_env = "sgx"),
|
||||
))] {
|
||||
mod gcc;
|
||||
|
|
|
@ -42,6 +42,7 @@ cfg_if::cfg_if! {
|
|||
target_os = "hurd",
|
||||
target_os = "l4re",
|
||||
target_os = "nto",
|
||||
target_os = "nuttx",
|
||||
))] {
|
||||
mod unix_legacy;
|
||||
pub use unix_legacy::fill_bytes;
|
||||
|
|
|
@ -21,6 +21,7 @@ cfg_if::cfg_if! {
|
|||
target_os = "haiku",
|
||||
target_os = "l4re",
|
||||
target_os = "nto",
|
||||
target_os = "nuttx",
|
||||
target_vendor = "apple",
|
||||
))] {
|
||||
use crate::sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#![doc(test(attr(deny(warnings))))]
|
||||
#![doc(rust_logo)]
|
||||
#![feature(rustdoc_internals)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(internal_output_capture)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(process_exitcode_internals)]
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::io::{self, BufReader};
|
||||
use std::path::Path;
|
||||
use std::{env, error, fmt};
|
||||
use std::{env, error, fmt, io};
|
||||
|
||||
use parm::{Param, Variables, expand};
|
||||
use parser::compiled::{msys_terminfo, parse};
|
||||
|
@ -102,8 +101,7 @@ impl TermInfo {
|
|||
}
|
||||
// Keep the metadata small
|
||||
fn _from_path(path: &Path) -> Result<TermInfo, Error> {
|
||||
let file = File::open(path).map_err(Error::IoError)?;
|
||||
let mut reader = BufReader::new(file);
|
||||
let mut reader = File::open_buffered(path).map_err(Error::IoError)?;
|
||||
parse(&mut reader, false).map_err(Error::MalformedTerminfo)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ cfg_if::cfg_if! {
|
|||
target_os = "none",
|
||||
target_os = "espidf",
|
||||
target_os = "rtems",
|
||||
target_os = "nuttx",
|
||||
))] {
|
||||
// These "unix" family members do not have unwinder.
|
||||
} else if #[cfg(any(
|
||||
|
|
|
@ -358,12 +358,14 @@ target | std | host | notes
|
|||
[`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF
|
||||
[`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF
|
||||
[`riscv32imafc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF
|
||||
[`riscv32-wrs-vxworks`](platform-support/vxworks.md) | ✓ | |
|
||||
[`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit
|
||||
`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD
|
||||
`riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia
|
||||
[`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | RISC-V NetBSD
|
||||
[`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64
|
||||
[`riscv64-linux-android`](platform-support/android.md) | | | RISC-V 64-bit Android
|
||||
[`riscv64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | |
|
||||
`s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, musl 1.2.3)
|
||||
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
|
||||
[`sparc-unknown-none-elf`](./platform-support/sparc-unknown-none-elf.md) | * | | Bare 32-bit SPARC V7+
|
||||
|
|
|
@ -14,6 +14,8 @@ Target triplets available:
|
|||
- `powerpc-wrs-vxworks`
|
||||
- `powerpc64-wrs-vxworks`
|
||||
- `powerpc-wrs-vxworks-spe`
|
||||
- `riscv32-wrs-vxworks`
|
||||
- `riscv64-wrs-vxworks`
|
||||
|
||||
## Target maintainers
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
use std::cell::RefCell;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufWriter, Write as _};
|
||||
use std::io::{self, Write as _};
|
||||
use std::iter::once;
|
||||
use std::marker::PhantomData;
|
||||
use std::path::{Component, Path, PathBuf};
|
||||
|
@ -1020,8 +1020,7 @@ where
|
|||
for part in parts {
|
||||
template.append(part);
|
||||
}
|
||||
let file = try_err!(File::create(&path), &path);
|
||||
let mut file = BufWriter::new(file);
|
||||
let mut file = try_err!(File::create_buffered(&path), &path);
|
||||
try_err!(write!(file, "{template}"), &path);
|
||||
try_err!(file.flush(), &path);
|
||||
}
|
||||
|
|
|
@ -286,7 +286,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
|||
|
||||
self.serialize_and_write(
|
||||
output_crate,
|
||||
BufWriter::new(try_err!(File::create(&p), p)),
|
||||
try_err!(File::create_buffered(&p), p),
|
||||
&p.display().to_string(),
|
||||
)
|
||||
} else {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#![feature(rustc_private)]
|
||||
#![feature(assert_matches)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(file_buffered)]
|
||||
#![feature(if_let_guard)]
|
||||
#![feature(impl_trait_in_assoc_type)]
|
||||
#![feature(iter_intersperse)]
|
||||
|
|
9
src/tools/clippy/.github/deploy.sh
vendored
9
src/tools/clippy/.github/deploy.sh
vendored
|
@ -25,16 +25,15 @@ if [[ $BETA = "true" ]]; then
|
|||
fi
|
||||
|
||||
# Generate version index that is shown as root index page
|
||||
cp util/gh-pages/versions.html out/index.html
|
||||
|
||||
echo "Making the versions.json file"
|
||||
python3 ./util/versions.py out
|
||||
python3 ./util/versions.py ./util/gh-pages/versions.html out
|
||||
|
||||
# Now let's go have some fun with the cloned repo
|
||||
cd out
|
||||
git config user.name "GHA CI"
|
||||
git config user.email "gha@ci.invalid"
|
||||
|
||||
git status
|
||||
|
||||
if [[ -n $TAG_NAME ]]; then
|
||||
# track files, so that the following check works
|
||||
git add --intent-to-add "$TAG_NAME"
|
||||
|
@ -46,8 +45,6 @@ if [[ -n $TAG_NAME ]]; then
|
|||
git add "$TAG_NAME"
|
||||
# Update the symlink
|
||||
git add stable
|
||||
# Update versions file
|
||||
git add versions.json
|
||||
git commit -m "Add documentation for ${TAG_NAME} release: ${SHA}"
|
||||
elif [[ $BETA = "true" ]]; then
|
||||
if git diff --exit-code --quiet -- beta/; then
|
||||
|
|
|
@ -162,7 +162,7 @@ jobs:
|
|||
find $DIR ! -executable -o -type d ! -path $DIR | xargs rm -rf
|
||||
|
||||
- name: Upload Binaries
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: binaries
|
||||
path: target/debug
|
||||
|
@ -202,7 +202,7 @@ jobs:
|
|||
|
||||
# Download
|
||||
- name: Download target dir
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: binaries
|
||||
path: target/debug
|
||||
|
|
|
@ -6,7 +6,61 @@ document.
|
|||
|
||||
## Unreleased / Beta / In Rust Nightly
|
||||
|
||||
[c9139bd5...master](https://github.com/rust-lang/rust-clippy/compare/c9139bd5...master)
|
||||
[b794b8e0...master](https://github.com/rust-lang/rust-clippy/compare/b794b8e0...master)
|
||||
|
||||
## Rust 1.81
|
||||
|
||||
Current stable, released 2024-09-05
|
||||
|
||||
### New Lints
|
||||
|
||||
* Added [`cfg_not_test`] to `restriction`
|
||||
[#11293](https://github.com/rust-lang/rust-clippy/pull/11293)
|
||||
* Added [`byte_char_slices`] to `style`
|
||||
[#10155](https://github.com/rust-lang/rust-clippy/pull/10155)
|
||||
* Added [`set_contains_or_insert`] to `nursery`
|
||||
[#12873](https://github.com/rust-lang/rust-clippy/pull/12873)
|
||||
* Added [`manual_rotate`] to `style`
|
||||
[#12983](https://github.com/rust-lang/rust-clippy/pull/12983)
|
||||
* Added [`unnecessary_min_or_max`] to `complexity`
|
||||
[#12368](https://github.com/rust-lang/rust-clippy/pull/12368)
|
||||
* Added [`manual_inspect`] to `complexity`
|
||||
[#12287](https://github.com/rust-lang/rust-clippy/pull/12287)
|
||||
* Added [`field_scoped_visibility_modifiers`] to `restriction`
|
||||
[#12893](https://github.com/rust-lang/rust-clippy/pull/12893)
|
||||
* Added [`manual_pattern_char_comparison`] to `style`
|
||||
[#12849](https://github.com/rust-lang/rust-clippy/pull/12849)
|
||||
* Added [`needless_maybe_sized`] to `suspicious`
|
||||
[#10632](https://github.com/rust-lang/rust-clippy/pull/10632)
|
||||
* Added [`needless_character_iteration`] to `suspicious`
|
||||
[#12815](https://github.com/rust-lang/rust-clippy/pull/12815)
|
||||
|
||||
### Moves and Deprecations
|
||||
|
||||
* [`allow_attributes`], [`allow_attributes_without_reason`]: Now work on stable
|
||||
[rust#120924](https://github.com/rust-lang/rust/pull/120924)
|
||||
* Renamed `overflow_check_conditional` to [`panicking_overflow_checks`]
|
||||
[#12944](https://github.com/rust-lang/rust-clippy/pull/12944)
|
||||
* Moved [`panicking_overflow_checks`] to `correctness` (From `complexity` now deny-by-default)
|
||||
[#12944](https://github.com/rust-lang/rust-clippy/pull/12944)
|
||||
* Renamed `thread_local_initializer_can_be_made_const` to [`missing_const_for_thread_local`]
|
||||
[#12974](https://github.com/rust-lang/rust-clippy/pull/12974)
|
||||
* Deprecated [`maybe_misused_cfg`] and [`mismatched_target_os`] as they are now caught by cargo
|
||||
and rustc
|
||||
[#12875](https://github.com/rust-lang/rust-clippy/pull/12875)
|
||||
|
||||
### Enhancements
|
||||
|
||||
* [`significant_drop_in_scrutinee`]: Now also checks scrutinies of `while let` and `for let`
|
||||
expressions
|
||||
[#12870](https://github.com/rust-lang/rust-clippy/pull/12870)
|
||||
* [`std_instead_of_core`]: Now respects the `msrv` configuration
|
||||
[#13168](https://github.com/rust-lang/rust-clippy/pull/13168)
|
||||
|
||||
### ICE Fixes
|
||||
|
||||
* [`suboptimal_flops`]: No longer crashes on custom `.log()` functions
|
||||
[#12884](https://github.com/rust-lang/rust-clippy/pull/12884)
|
||||
|
||||
## Rust 1.80
|
||||
|
||||
|
@ -5500,6 +5554,7 @@ Released 2018-09-13
|
|||
[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
|
||||
[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
|
||||
[`invalid_utf8_in_unchecked`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_utf8_in_unchecked
|
||||
[`inverted_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#inverted_saturating_sub
|
||||
[`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters
|
||||
[`is_digit_ascii_radix`]: https://rust-lang.github.io/rust-clippy/master/index.html#is_digit_ascii_radix
|
||||
[`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements
|
||||
|
@ -5559,6 +5614,7 @@ Released 2018-09-13
|
|||
[`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
|
||||
[`manual_c_str_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals
|
||||
[`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp
|
||||
[`manual_div_ceil`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_div_ceil
|
||||
[`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter
|
||||
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
|
||||
[`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
|
||||
|
@ -5570,6 +5626,7 @@ Released 2018-09-13
|
|||
[`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
|
||||
[`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite
|
||||
[`manual_is_infinite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_infinite
|
||||
[`manual_is_power_of_two`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two
|
||||
[`manual_is_variant_and`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_variant_and
|
||||
[`manual_let_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else
|
||||
[`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str
|
||||
|
@ -5716,6 +5773,7 @@ Released 2018-09-13
|
|||
[`non_minimal_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_minimal_cfg
|
||||
[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
|
||||
[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
|
||||
[`non_zero_suggestions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_zero_suggestions
|
||||
[`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool
|
||||
[`nonsensical_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonsensical_open_options
|
||||
[`nonstandard_macro_braces`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonstandard_macro_braces
|
||||
|
@ -5757,6 +5815,7 @@ Released 2018-09-13
|
|||
[`pathbuf_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#pathbuf_init_then_push
|
||||
[`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
|
||||
[`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false
|
||||
[`pointers_in_nomem_asm_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#pointers_in_nomem_asm_block
|
||||
[`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
|
||||
[`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
|
||||
[`precedence`]: https://rust-lang.github.io/rust-clippy/master/index.html#precedence
|
||||
|
@ -5962,6 +6021,7 @@ Released 2018-09-13
|
|||
[`unnecessary_fallible_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fallible_conversions
|
||||
[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
|
||||
[`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map
|
||||
[`unnecessary_first_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_first_then_check
|
||||
[`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
|
||||
[`unnecessary_get_then_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_get_then_check
|
||||
[`unnecessary_join`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_join
|
||||
|
@ -6003,6 +6063,7 @@ Released 2018-09-13
|
|||
[`unused_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_result_ok
|
||||
[`unused_rounding`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_rounding
|
||||
[`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self
|
||||
[`unused_trait_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_trait_names
|
||||
[`unused_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_unit
|
||||
[`unusual_byte_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#unusual_byte_groupings
|
||||
[`unwrap_in_result`]: https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_in_result
|
||||
|
@ -6013,6 +6074,7 @@ Released 2018-09-13
|
|||
[`use_debug`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_debug
|
||||
[`use_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#use_self
|
||||
[`used_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_binding
|
||||
[`used_underscore_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_items
|
||||
[`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref
|
||||
[`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute
|
||||
[`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
|
||||
|
@ -6047,6 +6109,7 @@ Released 2018-09-13
|
|||
[`zero_repeat_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_repeat_side_effects
|
||||
[`zero_sized_map_values`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_sized_map_values
|
||||
[`zero_width_space`]: https://rust-lang.github.io/rust-clippy/master/index.html#zero_width_space
|
||||
[`zombie_processes`]: https://rust-lang.github.io/rust-clippy/master/index.html#zombie_processes
|
||||
[`zst_offset`]: https://rust-lang.github.io/rust-clippy/master/index.html#zst_offset
|
||||
<!-- end autogenerated links to lint list -->
|
||||
<!-- begin autogenerated links to configuration documentation -->
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy"
|
||||
version = "0.1.82"
|
||||
version = "0.1.83"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
@ -31,7 +31,7 @@ anstream = "0.6.0"
|
|||
|
||||
[dev-dependencies]
|
||||
cargo_metadata = "0.18.1"
|
||||
ui_test = "0.25"
|
||||
ui_test = "0.26.4"
|
||||
regex = "1.5.5"
|
||||
serde = { version = "1.0.145", features = ["derive"] }
|
||||
serde_json = "1.0.122"
|
||||
|
|
|
@ -727,6 +727,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
|
|||
* [`uninlined_format_args`](https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args)
|
||||
* [`unnecessary_lazy_evaluations`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations)
|
||||
* [`unnested_or_patterns`](https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns)
|
||||
* [`unused_trait_names`](https://rust-lang.github.io/rust-clippy/master/index.html#unused_trait_names)
|
||||
* [`use_self`](https://rust-lang.github.io/rust-clippy/master/index.html#use_self)
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy_config"
|
||||
version = "0.1.82"
|
||||
version = "0.1.83"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ClippyConfiguration;
|
||||
use crate::msrvs::Msrv;
|
||||
use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename};
|
||||
use crate::ClippyConfiguration;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::edit_distance::edit_distance;
|
||||
|
@ -563,6 +563,7 @@ define_Conf! {
|
|||
uninlined_format_args,
|
||||
unnecessary_lazy_evaluations,
|
||||
unnested_or_patterns,
|
||||
unused_trait_names,
|
||||
use_self,
|
||||
)]
|
||||
msrv: Msrv = Msrv::empty(),
|
||||
|
@ -864,7 +865,7 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) {
|
|||
cmp::max(1, terminal_width / (SEPARATOR_WIDTH + max_field_width))
|
||||
});
|
||||
|
||||
let rows = (fields.len() + (columns - 1)) / columns;
|
||||
let rows = fields.len().div_ceil(columns);
|
||||
|
||||
let column_widths = (0..columns)
|
||||
.map(|column| {
|
||||
|
|
|
@ -26,5 +26,5 @@ mod metadata;
|
|||
pub mod msrvs;
|
||||
pub mod types;
|
||||
|
||||
pub use conf::{get_configuration_metadata, lookup_conf_file, Conf};
|
||||
pub use conf::{Conf, get_configuration_metadata, lookup_conf_file};
|
||||
pub use metadata::ClippyConfiguration;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use rustc_ast::Attribute;
|
||||
use rustc_attr::parse_version;
|
||||
use rustc_session::{RustcVersion, Session};
|
||||
use rustc_span::{sym, Symbol};
|
||||
use rustc_span::{Symbol, sym};
|
||||
use serde::Deserialize;
|
||||
use std::fmt;
|
||||
|
||||
|
@ -23,6 +23,7 @@ msrv_aliases! {
|
|||
1,80,0 { BOX_INTO_ITER}
|
||||
1,77,0 { C_STR_LITERALS }
|
||||
1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT }
|
||||
1,73,0 { MANUAL_DIV_CEIL }
|
||||
1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
|
||||
1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN }
|
||||
1,68,0 { PATH_MAIN_SEPARATOR_STR }
|
||||
|
@ -38,7 +39,7 @@ msrv_aliases! {
|
|||
1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST }
|
||||
1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS }
|
||||
1,50,0 { BOOL_THEN, CLAMP }
|
||||
1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN }
|
||||
1,47,0 { TAU, IS_ASCII_DIGIT_CONST, ARRAY_IMPL_ANY_LEN, SATURATING_SUB_CONST }
|
||||
1,46,0 { CONST_IF_MATCH }
|
||||
1,45,0 { STR_STRIP_PREFIX }
|
||||
1,43,0 { LOG2_10, LOG10_2, NUMERIC_ASSOCIATED_CONSTANTS }
|
||||
|
@ -50,6 +51,7 @@ msrv_aliases! {
|
|||
1,36,0 { ITERATOR_COPIED }
|
||||
1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
|
||||
1,34,0 { TRY_FROM }
|
||||
1,33,0 { UNDERSCORE_IMPORTS }
|
||||
1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
|
||||
1,29,0 { ITER_FLATTEN }
|
||||
1,28,0 { FROM_BOOL }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use serde::de::{self, Deserializer, Visitor};
|
||||
use serde::{ser, Deserialize, Serialize};
|
||||
use serde::{Deserialize, Serialize, ser};
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::clippy_project_root;
|
||||
use itertools::Itertools;
|
||||
use rustc_lexer::{tokenize, TokenKind};
|
||||
use rustc_lexer::{TokenKind, tokenize};
|
||||
use shell_escape::escape;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::ops::ControlFlow;
|
||||
|
|
|
@ -441,7 +441,7 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R
|
|||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> {
|
||||
use super::update_lints::{match_tokens, LintDeclSearchResult};
|
||||
use super::update_lints::{LintDeclSearchResult, match_tokens};
|
||||
use rustc_lexer::TokenKind;
|
||||
|
||||
let lint_name_upper = lint.name.to_uppercase();
|
||||
|
|
|
@ -29,7 +29,7 @@ pub fn run(port: u16, lint: Option<String>) -> ! {
|
|||
}
|
||||
if let Some(url) = url.take() {
|
||||
thread::spawn(move || {
|
||||
Command::new(PYTHON)
|
||||
let mut child = Command::new(PYTHON)
|
||||
.arg("-m")
|
||||
.arg("http.server")
|
||||
.arg(port.to_string())
|
||||
|
@ -40,6 +40,7 @@ pub fn run(port: u16, lint: Option<String>) -> ! {
|
|||
thread::sleep(Duration::from_millis(500));
|
||||
// Launch browser after first export.py has completed and http.server is up
|
||||
let _result = opener::open(url);
|
||||
child.wait().unwrap();
|
||||
});
|
||||
}
|
||||
thread::sleep(Duration::from_millis(1000));
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::clippy_project_root;
|
||||
use aho_corasick::AhoCorasickBuilder;
|
||||
use itertools::Itertools;
|
||||
use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
|
||||
use rustc_lexer::{LiteralKind, TokenKind, tokenize, unescape};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt::{self, Write};
|
||||
|
@ -1048,23 +1048,17 @@ mod tests {
|
|||
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
];
|
||||
let mut expected: HashMap<String, Vec<Lint>> = HashMap::new();
|
||||
expected.insert(
|
||||
"group1".to_string(),
|
||||
vec![
|
||||
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
],
|
||||
);
|
||||
expected.insert(
|
||||
"group2".to_string(),
|
||||
vec![Lint::new(
|
||||
"should_assert_eq2",
|
||||
"group2",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
)],
|
||||
);
|
||||
expected.insert("group1".to_string(), vec![
|
||||
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
Lint::new("incorrect_match", "group1", "\"abc\"", "module_name", Range::default()),
|
||||
]);
|
||||
expected.insert("group2".to_string(), vec![Lint::new(
|
||||
"should_assert_eq2",
|
||||
"group2",
|
||||
"\"abc\"",
|
||||
"module_name",
|
||||
Range::default(),
|
||||
)]);
|
||||
assert_eq!(expected, Lint::by_lint_group(lints.into_iter()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "clippy_lints"
|
||||
version = "0.1.82"
|
||||
version = "0.1.83"
|
||||
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
|
||||
repository = "https://github.com/rust-lang/rust-clippy"
|
||||
readme = "README.md"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue