diff --git a/src/doc/unstable-book/src/compiler-flags/tls-model.md b/src/doc/unstable-book/src/compiler-flags/tls-model.md new file mode 100644 index 0000000000000..0aefaa7fb0177 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/tls-model.md @@ -0,0 +1,25 @@ +# `tls_model` + +The tracking issue for this feature is: None. + +------------------------ + +Option `-Z tls-model` controls [TLS model](https://www.akkadia.org/drepper/tls.pdf) used to +generate code for accessing `#[thread_local]` `static` items. + +Supported values for this option are: + +- `global-dynamic` - General Dynamic TLS Model (alternatively called Global Dynamic) is the most +general option usable in all circumstances, even if the TLS data is defined in a shared library +loaded at runtime and is accessed from code outside of that library. +This is the default for most targets. +- `local-dynamic` - model usable if the TLS data is only accessed from the shared library or +executable it is defined in. The TLS data may be in a library loaded after startup (via `dlopen`). +- `initial-exec` - model usable if the TLS data is defined in the executable or in a shared library +loaded at program startup. +The TLS data must not be in a library loaded after startup (via `dlopen`). +- `local-exec` - model usable only if the TLS data is defined directly in the executable, +but not in a shared library, and is accessed only from that executable. + +`rustc` and LLVM may use a more optimized model than specified if they know that we are producing +and executable rather than a library, or that the `static` item is private enough. diff --git a/src/librustc_codegen_llvm/back/write.rs b/src/librustc_codegen_llvm/back/write.rs index bf79c5b593e48..3ec7ef831b54b 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -43,13 +43,6 @@ pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[ ("large", llvm::CodeModel::Large), ]; -pub const TLS_MODEL_ARGS: [(&str, llvm::ThreadLocalMode); 4] = [ - ("global-dynamic", llvm::ThreadLocalMode::GeneralDynamic), - ("local-dynamic", llvm::ThreadLocalMode::LocalDynamic), - ("initial-exec", llvm::ThreadLocalMode::InitialExec), - ("local-exec", llvm::ThreadLocalMode::LocalExec), -]; - pub fn llvm_err(handler: &rustc_errors::Handler, msg: &str) -> FatalError { match llvm::last_error() { Some(err) => handler.fatal(&format!("{}: {}", msg, err)), diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs index df442609052bb..f868385ee869a 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/src/librustc_codegen_llvm/context.rs @@ -21,7 +21,7 @@ use rustc_session::Session; use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_span::symbol::Symbol; use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx}; -use rustc_target::spec::{HasTargetSpec, RelocModel, Target}; +use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; use std::cell::{Cell, RefCell}; use std::ffi::CStr; @@ -87,19 +87,12 @@ pub struct CodegenCx<'ll, 'tcx> { local_gen_sym_counter: Cell, } -fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode { - let tls_model_arg = match sess.opts.debugging_opts.tls_model { - Some(ref s) => &s[..], - None => &sess.target.target.options.tls_model[..], - }; - - match crate::back::write::TLS_MODEL_ARGS.iter().find(|&&arg| arg.0 == tls_model_arg) { - Some(x) => x.1, - _ => { - sess.err(&format!("{:?} is not a valid TLS model", tls_model_arg)); - sess.abort_if_errors(); - bug!(); - } +fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode { + match tls_model { + TlsModel::GeneralDynamic => llvm::ThreadLocalMode::GeneralDynamic, + TlsModel::LocalDynamic => llvm::ThreadLocalMode::LocalDynamic, + TlsModel::InitialExec => llvm::ThreadLocalMode::InitialExec, + TlsModel::LocalExec => llvm::ThreadLocalMode::LocalExec, } } @@ -267,7 +260,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { let check_overflow = tcx.sess.overflow_checks(); - let tls_model = get_tls_model(&tcx.sess); + let tls_model = to_llvm_tls_model(tcx.sess.tls_model()); let (llcx, llmod) = (&*llvm_module.llcx, llvm_module.llmod()); diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs index 330d6ea75d273..42302a56b4188 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/src/librustc_codegen_llvm/lib.rs @@ -216,7 +216,7 @@ impl CodegenBackend for LlvmCodegenBackend { } PrintRequest::TlsModels => { println!("Available TLS models:"); - for &(name, _) in back::write::TLS_MODEL_ARGS.iter() { + for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec"] { println!(" {}", name); } println!(); diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index d342f8b0ad21c..654cd4980a4e1 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -1601,7 +1601,7 @@ pub enum ExprKind<'hir> { /// /// To resolve the path to a `DefId`, call [`qpath_res`]. /// -/// [`qpath_res`]: ../ty/struct.TypeckTables.html#method.qpath_res +/// [`qpath_res`]: ../rustc_middle/ty/struct.TypeckTables.html#method.qpath_res #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] pub enum QPath<'hir> { /// Path to a definition, optionally "fully-qualified" with a `Self` diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index f0e7581b76050..cee2e5b5becdb 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -14,7 +14,8 @@ use rustc_session::{build_session, Session}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use rustc_span::symbol::sym; use rustc_span::SourceFileHashAlgorithm; -use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelocModel, RelroLevel}; +use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy}; +use rustc_target::spec::{RelocModel, RelroLevel, TlsModel}; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; use std::path::PathBuf; @@ -567,7 +568,7 @@ fn test_debugging_options_tracking_hash() { tracked!(symbol_mangling_version, SymbolManglingVersion::V0); tracked!(teach, true); tracked!(thinlto, Some(true)); - tracked!(tls_model, Some(String::from("tls model"))); + tracked!(tls_model, Some(TlsModel::GeneralDynamic)); tracked!(treat_err_as_bug, Some(1)); tracked!(unleash_the_miri_inside_of_you, true); tracked!(verify_llvm_ir, true); diff --git a/src/librustc_session/config.rs b/src/librustc_session/config.rs index 1ab02f84c11a2..0dfc391d9cd3b 100644 --- a/src/librustc_session/config.rs +++ b/src/librustc_session/config.rs @@ -1315,10 +1315,6 @@ fn collect_print_requests( prints.push(PrintRequest::CodeModels); cg.code_model = None; } - if dopts.tls_model.as_ref().map_or(false, |s| s == "help") { - prints.push(PrintRequest::TlsModels); - dopts.tls_model = None; - } prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s { "crate-name" => PrintRequest::CrateName, @@ -2001,7 +1997,8 @@ crate mod dep_tracking { use crate::utils::NativeLibraryKind; use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; - use rustc_target::spec::{MergeFunctions, PanicStrategy, RelocModel, RelroLevel, TargetTriple}; + use rustc_target::spec::{MergeFunctions, PanicStrategy, RelocModel}; + use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel}; use std::collections::hash_map::DefaultHasher; use std::collections::BTreeMap; use std::hash::Hash; @@ -2050,6 +2047,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(Option>); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(Option); diff --git a/src/librustc_session/options.rs b/src/librustc_session/options.rs index 2279c16748c12..5b983d1105de4 100644 --- a/src/librustc_session/options.rs +++ b/src/librustc_session/options.rs @@ -6,7 +6,8 @@ use crate::search_paths::SearchPath; use crate::utils::NativeLibraryKind; use rustc_target::spec::TargetTriple; -use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelocModel, RelroLevel}; +use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy}; +use rustc_target::spec::{RelocModel, RelroLevel, TlsModel}; use rustc_feature::UnstableFeatures; use rustc_span::edition::Edition; @@ -267,6 +268,8 @@ macro_rules! options { pub const parse_src_file_hash: &str = "either `md5` or `sha1`"; pub const parse_relocation_model: &str = "one of supported relocation models (`rustc --print relocation-models`)"; + pub const parse_tls_model: &str = + "one of supported TLS models (`rustc --print tls-models`)"; } #[allow(dead_code)] @@ -606,6 +609,14 @@ macro_rules! options { true } + fn parse_tls_model(slot: &mut Option, v: Option<&str>) -> bool { + match v.and_then(|s| TlsModel::from_str(s).ok()) { + Some(tls_model) => *slot = Some(tls_model), + _ => return false, + } + true + } + fn parse_symbol_mangling_version( slot: &mut SymbolManglingVersion, v: Option<&str>, @@ -977,7 +988,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "measure time of each LLVM pass (default: no)"), time_passes: bool = (false, parse_bool, [UNTRACKED], "measure time of each rustc pass (default: no)"), - tls_model: Option = (None, parse_opt_string, [TRACKED], + tls_model: Option = (None, parse_tls_model, [TRACKED], "choose the TLS model to use (`rustc --print tls-models` for details)"), trace_macros: bool = (false, parse_bool, [UNTRACKED], "for every macro invocation, print its name and arguments (default: no)"), diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index 226d93920958f..42f9a8d6b0594 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -22,7 +22,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported use rustc_span::edition::Edition; use rustc_span::source_map::{self, FileLoader, MultiSpan, RealFileLoader, SourceMap, Span}; use rustc_span::SourceFileHashAlgorithm; -use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target, TargetTriple}; +use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target, TargetTriple, TlsModel}; use std::cell::{self, RefCell}; use std::env; @@ -588,6 +588,10 @@ impl Session { self.opts.cg.relocation_model.unwrap_or(self.target.target.options.relocation_model) } + pub fn tls_model(&self) -> TlsModel { + self.opts.debugging_opts.tls_model.unwrap_or(self.target.target.options.tls_model) + } + pub fn must_not_eliminate_frame_pointers(&self) -> bool { // "mcount" function relies on stack pointer. // See . diff --git a/src/librustc_target/spec/cloudabi_base.rs b/src/librustc_target/spec/cloudabi_base.rs index 53af9dcc18610..3659c9ecdfca6 100644 --- a/src/librustc_target/spec/cloudabi_base.rs +++ b/src/librustc_target/spec/cloudabi_base.rs @@ -1,4 +1,4 @@ -use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions}; +use crate::spec::{LinkArgs, LinkerFlavor, RelroLevel, TargetOptions, TlsModel}; pub fn opts() -> TargetOptions { let mut args = LinkArgs::new(); @@ -29,7 +29,7 @@ pub fn opts() -> TargetOptions { // (Global Offset Table) to obtain the effective address of a // thread-local variable. Using a GOT is useful only when doing // dynamic linking. - tls_model: "local-exec".to_string(), + tls_model: TlsModel::LocalExec, relro_level: RelroLevel::Full, ..Default::default() } diff --git a/src/librustc_target/spec/hermit_base.rs b/src/librustc_target/spec/hermit_base.rs index cb12055290e2e..18fb2aa3d5693 100644 --- a/src/librustc_target/spec/hermit_base.rs +++ b/src/librustc_target/spec/hermit_base.rs @@ -1,4 +1,5 @@ -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions}; +use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy}; +use crate::spec::{RelocModel, TargetOptions, TlsModel}; pub fn opts() -> TargetOptions { let mut pre_link_args = LinkArgs::new(); @@ -17,7 +18,7 @@ pub fn opts() -> TargetOptions { position_independent_executables: true, relocation_model: RelocModel::Static, target_family: None, - tls_model: "initial-exec".to_string(), + tls_model: TlsModel::InitialExec, ..Default::default() } } diff --git a/src/librustc_target/spec/hermit_kernel_base.rs b/src/librustc_target/spec/hermit_kernel_base.rs index 11599fda40906..7f2dada714d8f 100644 --- a/src/librustc_target/spec/hermit_kernel_base.rs +++ b/src/librustc_target/spec/hermit_kernel_base.rs @@ -1,4 +1,5 @@ -use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions}; +use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor, PanicStrategy}; +use crate::spec::{RelocModel, TargetOptions, TlsModel}; pub fn opts() -> TargetOptions { let mut pre_link_args = LinkArgs::new(); @@ -18,7 +19,7 @@ pub fn opts() -> TargetOptions { position_independent_executables: true, relocation_model: RelocModel::Static, target_family: None, - tls_model: "initial-exec".to_string(), + tls_model: TlsModel::InitialExec, ..Default::default() } } diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index 77fc78e81482c..e853c07632f90 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -305,6 +305,42 @@ impl ToJson for RelocModel { } } +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum TlsModel { + GeneralDynamic, + LocalDynamic, + InitialExec, + LocalExec, +} + +impl FromStr for TlsModel { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + // Note the difference "general" vs "global" difference. The model name is "general", + // but the user-facing option name is "global" for consistency with other compilers. + "global-dynamic" => TlsModel::GeneralDynamic, + "local-dynamic" => TlsModel::LocalDynamic, + "initial-exec" => TlsModel::InitialExec, + "local-exec" => TlsModel::LocalExec, + _ => return Err(()), + }) + } +} + +impl ToJson for TlsModel { + fn to_json(&self) -> Json { + match *self { + TlsModel::GeneralDynamic => "global-dynamic", + TlsModel::LocalDynamic => "local-dynamic", + TlsModel::InitialExec => "initial-exec", + TlsModel::LocalExec => "local-exec", + } + .to_json() + } +} + pub enum LoadTargetError { BuiltinTargetNotFound(String), Other(String), @@ -660,7 +696,7 @@ pub struct TargetOptions { pub code_model: Option, /// TLS model to use. Options are "global-dynamic" (default), "local-dynamic", "initial-exec" /// and "local-exec". This is similar to the -ftls-model option in GCC/Clang. - pub tls_model: String, + pub tls_model: TlsModel, /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false. pub disable_redzone: bool, /// Eliminate frame pointers from stack frames if possible. Defaults to true. @@ -863,7 +899,7 @@ impl Default for TargetOptions { executables: false, relocation_model: RelocModel::Pic, code_model: None, - tls_model: "global-dynamic".to_string(), + tls_model: TlsModel::GeneralDynamic, disable_redzone: false, eliminate_frame_pointer: true, function_sections: true, @@ -1060,6 +1096,18 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); + ($key_name:ident, TlsModel) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| { + match s.parse::() { + Ok(tls_model) => base.options.$key_name = tls_model, + _ => return Some(Err(format!("'{}' is not a valid TLS model. \ + Run `rustc --print tls-models` to \ + see the list of supported values.", s))), + } + Some(Ok(())) + })).unwrap_or(Ok(())) + } ); ($key_name:ident, PanicStrategy) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.find(&name[..]).and_then(|o| o.as_string().and_then(|s| { @@ -1200,7 +1248,7 @@ impl Target { key!(executables, bool); key!(relocation_model, RelocModel)?; key!(code_model, optional); - key!(tls_model); + key!(tls_model, TlsModel)?; key!(disable_redzone, bool); key!(eliminate_frame_pointer, bool); key!(function_sections, bool); diff --git a/src/librustc_target/spec/wasm32_base.rs b/src/librustc_target/spec/wasm32_base.rs index 08bade2abf4a9..bb19b9d00e8bf 100644 --- a/src/librustc_target/spec/wasm32_base.rs +++ b/src/librustc_target/spec/wasm32_base.rs @@ -1,4 +1,4 @@ -use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions}; +use super::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel}; use std::collections::BTreeMap; pub fn options() -> TargetOptions { @@ -138,7 +138,7 @@ pub fn options() -> TargetOptions { // `has_elf_tls`) and we need to get it to work by specifying // `local-exec` as that's all that's implemented in LLVM today for wasm. has_elf_tls: true, - tls_model: "local-exec".to_string(), + tls_model: TlsModel::LocalExec, // gdb scripts don't work on wasm blobs emit_debug_gdb_scripts: false, diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 8070ad1712025..3d665123f6767 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -211,12 +211,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::RawPtr(mt_b) => { return self.coerce_unsafe_ptr(a, b, mt_b.mutbl); } - - ty::Ref(r_b, ty, mutbl) => { - let mt_b = ty::TypeAndMut { ty, mutbl }; - return self.coerce_borrowed_pointer(a, b, r_b, mt_b); + ty::Ref(r_b, _, mutbl_b) => { + return self.coerce_borrowed_pointer(a, b, r_b, mutbl_b); } - _ => {} } @@ -255,7 +252,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { a: Ty<'tcx>, b: Ty<'tcx>, r_b: ty::Region<'tcx>, - mt_b: TypeAndMut<'tcx>, + mutbl_b: hir::Mutability, ) -> CoerceResult<'tcx> { debug!("coerce_borrowed_pointer(a={:?}, b={:?})", a, b); @@ -268,7 +265,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let (r_a, mt_a) = match a.kind { ty::Ref(r_a, ty, mutbl) => { let mt_a = ty::TypeAndMut { ty, mutbl }; - coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?; + coerce_mutbls(mt_a.mutbl, mutbl_b)?; (r_a, mt_a) } _ => return self.unify_and(a, b, identity), @@ -364,7 +361,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { r_a // [3] above } else { if r_borrow_var.is_none() { - // create var lazilly, at most once + // create var lazily, at most once let coercion = Coercion(span); let r = self.next_region_var(coercion); r_borrow_var = Some(r); // [4] above @@ -375,7 +372,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { r, TypeAndMut { ty: referent_ty, - mutbl: mt_b.mutbl, // [1] above + mutbl: mutbl_b, // [1] above }, ); match self.unify(derefd_ty_a, b) { @@ -417,11 +414,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // `self.x` both have `&mut `type would be a move of // `self.x`, but we auto-coerce it to `foo(&mut *self.x)`, // which is a borrow. - assert_eq!(mt_b.mutbl, hir::Mutability::Not); // can only coerce &T -> &U + assert_eq!(mutbl_b, hir::Mutability::Not); // can only coerce &T -> &U return success(vec![], ty, obligations); } - let needs = Needs::maybe_mut_place(mt_b.mutbl); + let needs = Needs::maybe_mut_place(mutbl_b); let InferOk { value: mut adjustments, obligations: o } = autoderef.adjust_steps_as_infer_ok(self, needs); obligations.extend(o); @@ -433,7 +430,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::Ref(r_borrow, _, _) => r_borrow, _ => span_bug!(span, "expected a ref type, got {:?}", ty), }; - let mutbl = match mt_b.mutbl { + let mutbl = match mutbl_b { hir::Mutability::Not => AutoBorrowMutability::Not, hir::Mutability::Mut => { AutoBorrowMutability::Mut { allow_two_phase_borrow: self.allow_two_phase } diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 119bdfcb0f442..f4c164a324e32 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -659,6 +659,11 @@ impl Read for File { self.inner.read_vectored(bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -674,6 +679,11 @@ impl Write for File { self.inner.write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { self.inner.flush() } @@ -694,6 +704,11 @@ impl Read for &File { self.inner.read_vectored(bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -709,6 +724,11 @@ impl Write for &File { self.inner.write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { self.inner.flush() } diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 16ca539b3c178..046b1a6888024 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -292,6 +292,10 @@ impl Read for BufReader { Ok(nread) } + fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + // we can't skip unconditionally because of the large buffer case in read. unsafe fn initializer(&self) -> Initializer { self.inner.initializer() @@ -680,6 +684,10 @@ impl Write for BufWriter { } } + fn is_write_vectored(&self) -> bool { + self.get_ref().is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { self.flush_buf().and_then(|()| self.get_mut().flush()) } diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index f36aa1846a16c..f3e3fc81a5d82 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -266,6 +266,10 @@ where Ok(nread) } + fn is_read_vectored(&self) -> bool { + true + } + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { let n = buf.len(); Read::read_exact(&mut self.fill_buf()?, buf)?; @@ -372,6 +376,11 @@ impl Write for Cursor<&mut [u8]> { slice_write_vectored(&mut self.pos, self.inner, bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -388,6 +397,11 @@ impl Write for Cursor<&mut Vec> { vec_write_vectored(&mut self.pos, self.inner, bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -404,6 +418,11 @@ impl Write for Cursor> { vec_write_vectored(&mut self.pos, &mut self.inner, bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -422,6 +441,11 @@ impl Write for Cursor> { slice_write_vectored(&mut self.pos, &mut self.inner, bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs index b7f82e652990d..01dff0b3eb390 100644 --- a/src/libstd/io/impls.rs +++ b/src/libstd/io/impls.rs @@ -20,6 +20,11 @@ impl Read for &mut R { (**self).read_vectored(bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + (**self).is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { (**self).initializer() @@ -52,6 +57,11 @@ impl Write for &mut W { (**self).write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + (**self).is_write_vectored() + } + #[inline] fn flush(&mut self) -> io::Result<()> { (**self).flush() @@ -109,6 +119,11 @@ impl Read for Box { (**self).read_vectored(bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + (**self).is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { (**self).initializer() @@ -141,6 +156,11 @@ impl Write for Box { (**self).write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + (**self).is_write_vectored() + } + #[inline] fn flush(&mut self) -> io::Result<()> { (**self).flush() @@ -240,6 +260,11 @@ impl Read for &[u8] { Ok(nread) } + #[inline] + fn is_read_vectored(&self) -> bool { + true + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -316,6 +341,11 @@ impl Write for &mut [u8] { Ok(nwritten) } + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + #[inline] fn write_all(&mut self, data: &[u8]) -> io::Result<()> { if self.write(data)? == data.len() { @@ -351,6 +381,11 @@ impl Write for Vec { Ok(len) } + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + #[inline] fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { self.extend_from_slice(buf); diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 5ab88260d6ac1..9cfb1728c04e4 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -256,6 +256,7 @@ //! [`Read::read`]: trait.Read.html#tymethod.read //! [`Result`]: ../result/enum.Result.html //! [`.unwrap()`]: ../result/enum.Result.html#method.unwrap +// ignore-tidy-filelength #![stable(feature = "rust1", since = "1.0.0")] @@ -580,6 +581,19 @@ pub trait Read { default_read_vectored(|b| self.read(b), bufs) } + /// Determines if this `Read`er has an efficient `read_vectored` + /// implementation. + /// + /// If a `Read`er does not override the default `read_vectored` + /// implementation, code using it may want to avoid the method all together + /// and coalesce writes into a single buffer for higher performance. + /// + /// The default implementation returns `false`. + #[unstable(feature = "can_vector", issue = "69941")] + fn is_read_vectored(&self) -> bool { + false + } + /// Determines if this `Read`er can work with buffers of uninitialized /// memory. /// @@ -1304,6 +1318,19 @@ pub trait Write { default_write_vectored(|b| self.write(b), bufs) } + /// Determines if this `Write`er has an efficient `write_vectored` + /// implementation. + /// + /// If a `Write`er does not override the default `write_vectored` + /// implementation, code using it may want to avoid the method all together + /// and coalesce writes into a single buffer for higher performance. + /// + /// The default implementation returns `false`. + #[unstable(feature = "can_vector", issue = "69941")] + fn is_write_vectored(&self) -> bool { + false + } + /// Flush this output stream, ensuring that all intermediately buffered /// contents reach their destination. /// diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index a064c552c84f5..b65b150d2c3a1 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -87,6 +87,11 @@ impl Read for StdinRaw { self.0.read_vectored(bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -101,6 +106,11 @@ impl Write for StdoutRaw { self.0.write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { self.0.flush() } @@ -114,6 +124,11 @@ impl Write for StderrRaw { self.0.write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { self.0.flush() } @@ -140,6 +155,14 @@ impl io::Write for Maybe { } } + #[inline] + fn is_write_vectored(&self) -> bool { + match self { + Maybe::Real(w) => w.is_write_vectored(), + Maybe::Fake => true, + } + } + fn flush(&mut self) -> io::Result<()> { match *self { Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()), @@ -162,6 +185,14 @@ impl io::Read for Maybe { Maybe::Fake => Ok(0), } } + + #[inline] + fn is_read_vectored(&self) -> bool { + match self { + Maybe::Real(w) => w.is_read_vectored(), + Maybe::Fake => true, + } + } } fn handle_ebadf(r: io::Result, default: T) -> io::Result { @@ -352,6 +383,10 @@ impl Read for Stdin { self.lock().read_vectored(bufs) } #[inline] + fn is_read_vectored(&self) -> bool { + self.lock().is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() } @@ -376,6 +411,11 @@ impl Read for StdinLock<'_> { self.inner.read_vectored(bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -543,6 +583,10 @@ impl Write for Stdout { fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.lock().write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.lock().is_write_vectored() + } fn flush(&mut self) -> io::Result<()> { self.lock().flush() } @@ -561,6 +605,10 @@ impl Write for StdoutLock<'_> { fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.inner.borrow_mut().write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.inner.borrow_mut().is_write_vectored() + } fn flush(&mut self) -> io::Result<()> { self.inner.borrow_mut().flush() } @@ -709,6 +757,10 @@ impl Write for Stderr { fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.lock().write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.lock().is_write_vectored() + } fn flush(&mut self) -> io::Result<()> { self.lock().flush() } @@ -727,6 +779,10 @@ impl Write for StderrLock<'_> { fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { self.inner.borrow_mut().write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.inner.borrow_mut().is_write_vectored() + } fn flush(&mut self) -> io::Result<()> { self.inner.borrow_mut().flush() } diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs index b09161b97aa5e..b9d5dc27db006 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -179,6 +179,11 @@ impl Read for Repeat { Ok(nwritten) } + #[inline] + fn is_read_vectored(&self) -> bool { + true + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -235,6 +240,11 @@ impl Write for Sink { Ok(total_len) } + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 5fd15bb8fe4f3..ac07af5e278fb 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -243,6 +243,7 @@ #![feature(box_syntax)] #![feature(c_variadic)] #![feature(cfg_accessible)] +#![feature(can_vector)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] #![feature(char_error_internals)] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 5023d69240893..9ac54dd5f7a65 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -576,6 +576,11 @@ impl Read for TcpStream { self.0.read_vectored(bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -591,6 +596,11 @@ impl Write for TcpStream { self.0.write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -605,6 +615,11 @@ impl Read for &TcpStream { self.0.read_vectored(bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -620,6 +635,11 @@ impl Write for &TcpStream { self.0.write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 3eee45d000cd1..b457d190b9510 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -245,6 +245,10 @@ impl Write for ChildStdin { self.inner.write_vectored(bufs) } + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -300,6 +304,11 @@ impl Read for ChildStdout { self.inner.read_vectored(bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -356,6 +365,11 @@ impl Read for ChildStderr { self.inner.read_vectored(bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() diff --git a/src/libstd/sys/cloudabi/shims/fs.rs b/src/libstd/sys/cloudabi/shims/fs.rs index e6160d1457d26..ecb5b51cccdcd 100644 --- a/src/libstd/sys/cloudabi/shims/fs.rs +++ b/src/libstd/sys/cloudabi/shims/fs.rs @@ -202,6 +202,10 @@ impl File { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } @@ -210,6 +214,10 @@ impl File { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } diff --git a/src/libstd/sys/cloudabi/shims/net.rs b/src/libstd/sys/cloudabi/shims/net.rs index 67c436fa7955d..375aaab405dff 100644 --- a/src/libstd/sys/cloudabi/shims/net.rs +++ b/src/libstd/sys/cloudabi/shims/net.rs @@ -47,6 +47,10 @@ impl TcpStream { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _: &[u8]) -> io::Result { match self.0 {} } @@ -55,6 +59,10 @@ impl TcpStream { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn peer_addr(&self) -> io::Result { match self.0 {} } diff --git a/src/libstd/sys/cloudabi/shims/pipe.rs b/src/libstd/sys/cloudabi/shims/pipe.rs index fb14dc5910181..10d0925823eb9 100644 --- a/src/libstd/sys/cloudabi/shims/pipe.rs +++ b/src/libstd/sys/cloudabi/shims/pipe.rs @@ -12,6 +12,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } @@ -20,6 +24,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/hermit/fs.rs b/src/libstd/sys/hermit/fs.rs index 287a039066780..82ccab1462ba8 100644 --- a/src/libstd/sys/hermit/fs.rs +++ b/src/libstd/sys/hermit/fs.rs @@ -301,6 +301,11 @@ impl File { crate::io::default_read_vectored(|buf| self.read(buf), bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + false + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } @@ -309,6 +314,11 @@ impl File { crate::io::default_write_vectored(|buf| self.write(buf), bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + false + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } diff --git a/src/libstd/sys/hermit/net.rs b/src/libstd/sys/hermit/net.rs index 377c3132c5a32..5b5379c8b0581 100644 --- a/src/libstd/sys/hermit/net.rs +++ b/src/libstd/sys/hermit/net.rs @@ -99,6 +99,11 @@ impl TcpStream { Ok(size) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn write(&self, buffer: &[u8]) -> io::Result { self.write_vectored(&[IoSlice::new(buffer)]) } @@ -114,6 +119,11 @@ impl TcpStream { Ok(size) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn peer_addr(&self) -> io::Result { Err(io::Error::new(ErrorKind::Other, "peer_addr isn't supported")) } diff --git a/src/libstd/sys/hermit/pipe.rs b/src/libstd/sys/hermit/pipe.rs index fb14dc5910181..10d0925823eb9 100644 --- a/src/libstd/sys/hermit/pipe.rs +++ b/src/libstd/sys/hermit/pipe.rs @@ -12,6 +12,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } @@ -20,6 +24,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/hermit/stdio.rs b/src/libstd/sys/hermit/stdio.rs index 2eb011ccb3974..208265de465ad 100644 --- a/src/libstd/sys/hermit/stdio.rs +++ b/src/libstd/sys/hermit/stdio.rs @@ -20,6 +20,11 @@ impl Stdin { // .read(data) Ok(0) } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } } impl Stdout { @@ -51,6 +56,11 @@ impl Stdout { } } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } @@ -85,6 +95,11 @@ impl Stderr { } } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } diff --git a/src/libstd/sys/sgx/fd.rs b/src/libstd/sys/sgx/fd.rs index 7da2424a64261..90158030c7fbe 100644 --- a/src/libstd/sys/sgx/fd.rs +++ b/src/libstd/sys/sgx/fd.rs @@ -34,6 +34,11 @@ impl FileDesc { usercalls::read(self.fd, bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn write(&self, buf: &[u8]) -> io::Result { usercalls::write(self.fd, &[IoSlice::new(buf)]) } @@ -42,6 +47,11 @@ impl FileDesc { usercalls::write(self.fd, bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { usercalls::flush(self.fd) } diff --git a/src/libstd/sys/sgx/fs.rs b/src/libstd/sys/sgx/fs.rs index e6160d1457d26..ecb5b51cccdcd 100644 --- a/src/libstd/sys/sgx/fs.rs +++ b/src/libstd/sys/sgx/fs.rs @@ -202,6 +202,10 @@ impl File { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } @@ -210,6 +214,10 @@ impl File { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs index bd0652ab4649a..666a157b09cd0 100644 --- a/src/libstd/sys/sgx/net.rs +++ b/src/libstd/sys/sgx/net.rs @@ -149,6 +149,11 @@ impl TcpStream { self.inner.inner.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.inner.inner.is_read_vectored() + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.inner.inner.write(buf) } @@ -157,6 +162,11 @@ impl TcpStream { self.inner.inner.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.inner.inner.is_write_vectored() + } + pub fn peer_addr(&self) -> io::Result { addr_to_sockaddr(&self.peer_addr) } diff --git a/src/libstd/sys/sgx/pipe.rs b/src/libstd/sys/sgx/pipe.rs index fb14dc5910181..10d0925823eb9 100644 --- a/src/libstd/sys/sgx/pipe.rs +++ b/src/libstd/sys/sgx/pipe.rs @@ -12,6 +12,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } @@ -20,6 +24,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 4c3cb67c9ee0f..bfdc39ada75eb 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -613,6 +613,11 @@ impl io::Read for UnixStream { io::Read::read_vectored(&mut &*self, bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + io::Read::is_read_vectored(&&*self) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -629,6 +634,11 @@ impl<'a> io::Read for &'a UnixStream { self.0.read_vectored(bufs) } + #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -645,6 +655,11 @@ impl io::Write for UnixStream { io::Write::write_vectored(&mut &*self, bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + fn flush(&mut self) -> io::Result<()> { io::Write::flush(&mut &*self) } @@ -660,6 +675,11 @@ impl<'a> io::Write for &'a UnixStream { self.0.write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 1bba56e334a2e..1ef7ffacfcf14 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -64,6 +64,11 @@ impl FileDesc { Ok(ret as usize) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { let mut me = self; (&mut me).read_to_end(buf) @@ -116,6 +121,11 @@ impl FileDesc { Ok(ret as usize) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { #[cfg(target_os = "android")] use super::android::cvt_pwrite64; diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index a233aa47dff58..2cfc63d94922d 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -828,6 +828,11 @@ impl File { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { self.0.read_at(buf, offset) } @@ -840,6 +845,11 @@ impl File { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { self.0.write_at(buf, offset) } diff --git a/src/libstd/sys/unix/l4re.rs b/src/libstd/sys/unix/l4re.rs index c6e4f5693ed5a..a2912387108e1 100644 --- a/src/libstd/sys/unix/l4re.rs +++ b/src/libstd/sys/unix/l4re.rs @@ -55,6 +55,10 @@ pub mod net { unimpl!(); } + pub fn is_read_vectored(&self) -> bool { + unimpl!(); + } + pub fn peek(&self, _: &mut [u8]) -> io::Result { unimpl!(); } @@ -75,6 +79,10 @@ pub mod net { unimpl!(); } + pub fn is_write_vectored(&self) -> bool { + unimpl!(); + } + pub fn set_timeout(&self, _: Option, _: libc::c_int) -> io::Result<()> { unimpl!(); } @@ -171,6 +179,10 @@ pub mod net { unimpl!(); } + pub fn is_read_vectored(&self) -> bool { + unimpl!(); + } + pub fn write(&self, _: &[u8]) -> io::Result { unimpl!(); } @@ -179,6 +191,10 @@ pub mod net { unimpl!(); } + pub fn is_write_vectored(&self) -> bool { + unimpl!(); + } + pub fn peer_addr(&self) -> io::Result { unimpl!(); } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index d18c22b0573f3..f062bc012f7ef 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -226,6 +226,11 @@ impl Socket { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn recv_from_with_flags( &self, buf: &mut [u8], @@ -263,6 +268,11 @@ impl Socket { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn set_timeout(&self, dur: Option, kind: libc::c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 2a861c878015e..f2a2eabef9132 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -64,6 +64,11 @@ impl AnonPipe { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } @@ -72,6 +77,11 @@ impl AnonPipe { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn fd(&self) -> &FileDesc { &self.0 } diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index b9c56963885c0..f8353214cbca0 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -20,6 +20,11 @@ impl io::Read for Stdin { fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read_vectored(bufs) } + + #[inline] + fn is_read_vectored(&self) -> bool { + true + } } impl Stdout { @@ -37,6 +42,11 @@ impl io::Write for Stdout { ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -57,6 +67,11 @@ impl io::Write for Stderr { ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } diff --git a/src/libstd/sys/vxworks/fd.rs b/src/libstd/sys/vxworks/fd.rs index 65c67dabc1ad0..23e9dc428ce23 100644 --- a/src/libstd/sys/vxworks/fd.rs +++ b/src/libstd/sys/vxworks/fd.rs @@ -54,6 +54,11 @@ impl FileDesc { Ok(ret as usize) } + #[inline] + fn is_read_vectored(&self) -> bool { + true + } + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { let mut me = self; (&mut me).read_to_end(buf) @@ -99,6 +104,11 @@ impl FileDesc { Ok(ret as usize) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { unsafe fn cvt_pwrite( fd: c_int, diff --git a/src/libstd/sys/vxworks/fs.rs b/src/libstd/sys/vxworks/fs.rs index 68f2c13317024..557e65ca01b1c 100644 --- a/src/libstd/sys/vxworks/fs.rs +++ b/src/libstd/sys/vxworks/fs.rs @@ -351,6 +351,11 @@ impl File { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { self.0.read_at(buf, offset) } @@ -363,6 +368,11 @@ impl File { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { self.0.write_at(buf, offset) } diff --git a/src/libstd/sys/vxworks/net.rs b/src/libstd/sys/vxworks/net.rs index 7d4e5624f7e39..de0b15b43a2e2 100644 --- a/src/libstd/sys/vxworks/net.rs +++ b/src/libstd/sys/vxworks/net.rs @@ -163,6 +163,11 @@ impl Socket { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn recv_from_with_flags( &self, buf: &mut [u8], @@ -200,6 +205,11 @@ impl Socket { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn set_timeout(&self, dur: Option, kind: libc::c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { diff --git a/src/libstd/sys/vxworks/pipe.rs b/src/libstd/sys/vxworks/pipe.rs index 0990cb8e83cf8..a18376212af51 100644 --- a/src/libstd/sys/vxworks/pipe.rs +++ b/src/libstd/sys/vxworks/pipe.rs @@ -24,10 +24,16 @@ impl AnonPipe { pub fn read(&self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.0.write(buf) } @@ -36,6 +42,11 @@ impl AnonPipe { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn fd(&self) -> &FileDesc { &self.0 } diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index a11f61fdd69fd..793daea43c215 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -399,6 +399,11 @@ impl File { self.fd.read(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.write_vectored(&[IoSlice::new(buf)]) } @@ -407,6 +412,11 @@ impl File { self.fd.write(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } diff --git a/src/libstd/sys/wasi/net.rs b/src/libstd/sys/wasi/net.rs index 8a69028ff1dcf..e186453588de5 100644 --- a/src/libstd/sys/wasi/net.rs +++ b/src/libstd/sys/wasi/net.rs @@ -48,6 +48,10 @@ impl TcpStream { unsupported() } + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn write(&self, _: &[u8]) -> io::Result { unsupported() } @@ -56,6 +60,10 @@ impl TcpStream { unsupported() } + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn peer_addr(&self) -> io::Result { unsupported() } diff --git a/src/libstd/sys/wasi/pipe.rs b/src/libstd/sys/wasi/pipe.rs index fb14dc5910181..10d0925823eb9 100644 --- a/src/libstd/sys/wasi/pipe.rs +++ b/src/libstd/sys/wasi/pipe.rs @@ -12,6 +12,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } @@ -20,6 +24,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/wasi/stdio.rs b/src/libstd/sys/wasi/stdio.rs index 1d53884f2d6b4..9f9e35566ecf5 100644 --- a/src/libstd/sys/wasi/stdio.rs +++ b/src/libstd/sys/wasi/stdio.rs @@ -19,6 +19,11 @@ impl Stdin { ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).read(data) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn as_raw_fd(&self) -> u32 { 0 } @@ -37,6 +42,11 @@ impl Stdout { ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } @@ -59,6 +69,11 @@ impl Stderr { ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/wasm/fs.rs index e6160d1457d26..ecb5b51cccdcd 100644 --- a/src/libstd/sys/wasm/fs.rs +++ b/src/libstd/sys/wasm/fs.rs @@ -202,6 +202,10 @@ impl File { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } @@ -210,6 +214,10 @@ impl File { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/wasm/net.rs index b7c3108f172f6..5c9f1098f9b7f 100644 --- a/src/libstd/sys/wasm/net.rs +++ b/src/libstd/sys/wasm/net.rs @@ -44,6 +44,10 @@ impl TcpStream { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _: &[u8]) -> io::Result { match self.0 {} } @@ -52,6 +56,10 @@ impl TcpStream { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn peer_addr(&self) -> io::Result { match self.0 {} } diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/wasm/pipe.rs index fb14dc5910181..10d0925823eb9 100644 --- a/src/libstd/sys/wasm/pipe.rs +++ b/src/libstd/sys/wasm/pipe.rs @@ -12,6 +12,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result { match self.0 {} } @@ -20,6 +24,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 427f4b684e14a..cdbfac267b9a1 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -409,6 +409,11 @@ impl File { self.handle.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.handle.is_read_vectored() + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { self.handle.read_at(buf, offset) } @@ -421,6 +426,11 @@ impl File { self.handle.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.handle.is_write_vectored() + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { self.handle.write_at(buf, offset) } diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index d00381792e351..2131cfc2c94bc 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -92,6 +92,11 @@ impl RawHandle { crate::io::default_read_vectored(|buf| self.read(buf), bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + false + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { let mut read = 0; let len = cmp::min(buf.len(), ::max_value() as usize) as c::DWORD; @@ -171,6 +176,11 @@ impl RawHandle { crate::io::default_write_vectored(|buf| self.write(buf), bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + false + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { let mut written = 0; let len = cmp::min(buf.len(), ::max_value() as usize) as c::DWORD; diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index d8d4fdfce2fe4..a15ded92f08c4 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -266,6 +266,11 @@ impl Socket { } } + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn peek(&self, buf: &mut [u8]) -> io::Result { self.recv_with_flags(buf, c::MSG_PEEK) } @@ -324,6 +329,11 @@ impl Socket { Ok(nwritten as usize) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn set_timeout(&self, dur: Option, kind: c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 992e634dea510..104a8db46596e 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -182,6 +182,11 @@ impl AnonPipe { self.inner.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + pub fn write(&self, buf: &[u8]) -> io::Result { self.inner.write(buf) } @@ -189,6 +194,11 @@ impl AnonPipe { pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { self.inner.write_vectored(bufs) } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } } pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> io::Result<()> { diff --git a/src/libstd/sys_common/net.rs b/src/libstd/sys_common/net.rs index cdd3d2edf1fa1..a9b6079de7564 100644 --- a/src/libstd/sys_common/net.rs +++ b/src/libstd/sys_common/net.rs @@ -265,6 +265,11 @@ impl TcpStream { self.inner.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + pub fn write(&self, buf: &[u8]) -> io::Result { let len = cmp::min(buf.len(), ::max_value() as usize) as wrlen_t; let ret = cvt(unsafe { @@ -277,6 +282,11 @@ impl TcpStream { self.inner.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + pub fn peer_addr(&self) -> io::Result { sockname(|buf, len| unsafe { c::getpeername(*self.inner.as_inner(), buf, len) }) } diff --git a/src/test/ui/consts/recursive-zst-static.stderr b/src/test/ui/consts/recursive-zst-static.default.stderr similarity index 81% rename from src/test/ui/consts/recursive-zst-static.stderr rename to src/test/ui/consts/recursive-zst-static.default.stderr index e21dcf691ab0a..d424b22f000bf 100644 --- a/src/test/ui/consts/recursive-zst-static.stderr +++ b/src/test/ui/consts/recursive-zst-static.default.stderr @@ -1,17 +1,17 @@ error[E0391]: cycle detected when const-evaluating `FOO` - --> $DIR/recursive-zst-static.rs:7:18 + --> $DIR/recursive-zst-static.rs:10:18 | LL | static FOO: () = FOO; | ^^^ | note: ...which requires const-evaluating `FOO`... - --> $DIR/recursive-zst-static.rs:7:1 + --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires const-evaluating `FOO`, completing the cycle note: cycle used when const-evaluating + checking `FOO` - --> $DIR/recursive-zst-static.rs:7:1 + --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/consts/recursive-zst-static.rs b/src/test/ui/consts/recursive-zst-static.rs index 768df58e1e32e..29a467c006a49 100644 --- a/src/test/ui/consts/recursive-zst-static.rs +++ b/src/test/ui/consts/recursive-zst-static.rs @@ -1,3 +1,6 @@ +// revisions: default unleash +//[unleash]compile-flags: -Zunleash-the-miri-inside-of-you + // This test ensures that we do not allow ZST statics to initialize themselves without ever // actually creating a value of that type. This is important, as the ZST may have private fields // that users can reasonably expect to only get initialized by their own code. Thus unsafe code diff --git a/src/test/ui/consts/recursive-zst-static.unleash.stderr b/src/test/ui/consts/recursive-zst-static.unleash.stderr new file mode 100644 index 0000000000000..d424b22f000bf --- /dev/null +++ b/src/test/ui/consts/recursive-zst-static.unleash.stderr @@ -0,0 +1,21 @@ +error[E0391]: cycle detected when const-evaluating `FOO` + --> $DIR/recursive-zst-static.rs:10:18 + | +LL | static FOO: () = FOO; + | ^^^ + | +note: ...which requires const-evaluating `FOO`... + --> $DIR/recursive-zst-static.rs:10:1 + | +LL | static FOO: () = FOO; + | ^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires const-evaluating `FOO`, completing the cycle +note: cycle used when const-evaluating + checking `FOO` + --> $DIR/recursive-zst-static.rs:10:1 + | +LL | static FOO: () = FOO; + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0391`. diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index fb4611ed1ca4b..570ffd5d30622 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -114,7 +114,7 @@ fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) { } fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Option { - // Ignore none HTML files. + // Ignore non-HTML files. if file.extension().and_then(|s| s.to_str()) != Some("html") { return None; } diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 243d41598f86c..f7fd0c670d704 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -17,7 +17,7 @@ const WHITELIST: &[&str] = &[ // Some error codes don't have any tests apparently... const IGNORE_EXPLANATION_CHECK: &[&str] = - &["E0570", "E0601", "E0602", "E0639", "E0729", "E0749", "E0750", "E0751"]; + &["E0570", "E0601", "E0602", "E0639", "E0729", "E0749", "E0750"]; fn check_error_code_explanation( f: &str,