uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
env:
DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
os: ubuntu-latest-xl
+ - name: dist-x86_64-apple
+ env:
+ SCRIPT: "./x.py dist"
+ RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ DIST_REQUIRE_ALL_TOOLS: 1
+ os: macos-latest
+ - name: dist-x86_64-apple-alt
+ env:
+ SCRIPT: "./x.py dist"
+ RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ os: macos-latest
+ - name: x86_64-apple
+ env:
+ SCRIPT: "./x.py --stage 2 test"
+ RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.8
+ MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ os: macos-latest
+ - name: dist-x86_64-apple
+ env:
+ SCRIPT: "./x.py dist"
+ RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ DIST_REQUIRE_ALL_TOOLS: 1
+ os: macos-latest
+ - name: dist-x86_64-apple-alt
+ env:
+ SCRIPT: "./x.py dist"
+ RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ os: macos-latest
+ - name: x86_64-apple
+ env:
+ SCRIPT: "./x.py --stage 2 test"
+ RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.8
+ MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ os: macos-latest
- name: x86_64-msvc-1
env:
RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler"
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
- self-hosted
- ARM64
- linux
- - name: dist-x86_64-apple
- env:
- SCRIPT: "./x.py dist"
- RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- DIST_REQUIRE_ALL_TOOLS: 1
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- os: macos-latest
- - name: dist-x86_64-apple-alt
- env:
- SCRIPT: "./x.py dist"
- RUST_CONFIGURE_ARGS: "--enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- os: macos-latest
- - name: x86_64-apple
- env:
- SCRIPT: "./x.py --stage 2 test"
- RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.8
- MACOSX_STD_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- os: macos-latest
timeout-minutes: 600
runs-on: "${{ matrix.os }}"
steps:
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED"
+ if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
- name: collect CPU statistics
run: src/ci/scripts/collect-cpu-stats.sh
if: success() && !env.SKIP_JOB
Chris Pressey <cpressey@gmail.com>
Chris Thorn <chris@thorn.co> Chris Thorn <thorn@thoughtbot.com>
Chris Vittal <christopher.vittal@gmail.com> Christopher Vittal <christopher.vittal@gmail.com>
+Christiaan Dirkx <christiaan@dirkx.email> <christiaan@dirkx.com>
+Christiaan Dirkx <christiaan@dirkx.email> CDirkx <christiaan@dirkx.com>
+Christiaan Dirkx <christiaan@dirkx.email> CDirkx <christiaan@dirkx.email>
Christian Poveda <git@christianpoveda.xyz> <christianpoveda@protonmail.com>
Christian Poveda <git@christianpoveda.xyz> <cn.poveda.ruiz@gmail.com>
Christian Poveda <git@christianpoveda.xyz> <z1mvader@protonmail.com>
"if_chain",
"itertools 0.9.0",
"lazy_static",
- "pulldown-cmark",
+ "pulldown-cmark 0.7.2",
"quine-mc_cluskey",
"quote",
"regex-syntax",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
+[[package]]
+name = "lint-docs"
+version = "0.1.0"
+dependencies = [
+ "serde_json",
+ "tempfile",
+ "walkdir",
+]
+
[[package]]
name = "lock_api"
version = "0.3.4"
"log",
"memchr",
"open",
- "pulldown-cmark",
+ "pulldown-cmark 0.7.2",
"regex",
"serde",
"serde_derive",
"unicase",
]
+[[package]]
+name = "pulldown-cmark"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
+dependencies = [
+ "bitflags",
+ "memchr",
+ "unicase",
+]
+
[[package]]
name = "punycode"
version = "0.4.1"
"rustc_data_structures",
"rustc_errors",
"rustc_expand",
+ "rustc_feature",
"rustc_hir",
"rustc_hir_pretty",
"rustc_index",
"expect-test",
"itertools 0.9.0",
"minifier",
- "pulldown-cmark",
+ "pulldown-cmark 0.8.0",
"rustc-rayon",
"serde",
"serde_json",
"src/tools/compiletest",
"src/tools/error_index_generator",
"src/tools/linkchecker",
+ "src/tools/lint-docs",
"src/tools/rustbook",
"src/tools/unstable-book-gen",
"src/tools/tidy",
fn sort_by_words(name: &str) -> String {
let mut split_words: Vec<&str> = name.split('_').collect();
- split_words.sort();
+ // We are sorting primitive &strs and can use unstable sort here
+ split_words.sort_unstable();
split_words.join("_")
}
// features. We check that at least one type is available for
// the current target.
let reg_class = reg.reg_class();
- let mut required_features = vec![];
+ let mut required_features: Vec<&str> = vec![];
for &(_, feature) in reg_class.supported_types(asm_arch) {
if let Some(feature) = feature {
if self.sess.target_features.contains(&Symbol::intern(feature)) {
break;
}
}
- required_features.sort();
+ // We are sorting primitive strs here and can use unstable sort here
+ required_features.sort_unstable();
required_features.dedup();
match &required_features[..] {
[] => {}
cfg => doc_cfg
masked => doc_masked
spotlight => doc_spotlight
- alias => doc_alias
keyword => doc_keyword
);
}
let start = match start {
Bound::Included(lo) => lo,
- Bound::Excluded(lo) => lo + 1,
+ Bound::Excluded(lo) => lo.checked_add(1)?,
Bound::Unbounded => 0,
};
let end = match end {
- Bound::Included(hi) => hi + 1,
+ Bound::Included(hi) => hi.checked_add(1)?,
Bound::Excluded(hi) => hi,
Bound::Unbounded => length,
};
/// Allows `#[track_caller]` to be used which provides
/// accurate caller location reporting during panic (RFC 2091).
(accepted, track_caller, "1.46.0", Some(47809), None),
+ /// Allows `#[doc(alias = "...")]`.
+ (accepted, doc_alias, "1.48.0", Some(50146), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
/// Allows dereferencing raw pointers during const eval.
(active, const_raw_ptr_deref, "1.27.0", Some(51911), None),
- /// Allows `#[doc(alias = "...")]`.
- (active, doc_alias, "1.27.0", Some(50146), None),
-
/// Allows inconsistent bounds in where clauses.
(active, trivial_bounds, "1.28.0", Some(48214), None),
// Type namespace
PrimTy(hir::PrimTy),
- SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),
+ /// `Self`, with both an optional trait and impl `DefId`.
+ ///
+ /// HACK(min_const_generics): impl self types also have an optional requirement to not mention
+ /// any generic parameters to allow the following with `min_const_generics`:
+ /// ```rust
+ /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] {} }
+ /// ```
+ ///
+ /// FIXME(lazy_normalization_consts): Remove this bodge once this feature is stable.
+ SelfTy(Option<DefId> /* trait */, Option<(DefId, bool)> /* impl */),
ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]`
// Value namespace
subst::{Subst, SubstsRef},
Region, Ty, TyCtxt, TypeFoldable,
};
-use rustc_span::{DesugaringKind, Pos, Span};
+use rustc_span::{BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
use std::{cmp, fmt};
ref prior_arms,
last_ty,
scrut_hir_id,
+ opt_suggest_box_span,
+ arm_span,
..
}) => match source {
hir::MatchSource::IfLetDesugar { .. } => {
let msg = "`if let` arms have incompatible types";
err.span_label(cause.span, msg);
+ if let Some(ret_sp) = opt_suggest_box_span {
+ self.suggest_boxing_for_return_impl_trait(
+ err,
+ ret_sp,
+ prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
+ );
+ }
}
hir::MatchSource::TryDesugar => {
if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
Applicability::MachineApplicable,
);
}
+ if let Some(ret_sp) = opt_suggest_box_span {
+ // Get return type span and point to it.
+ self.suggest_boxing_for_return_impl_trait(
+ err,
+ ret_sp,
+ prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
+ );
+ }
}
},
- ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => {
+ ObligationCauseCode::IfExpression(box IfExpressionCause {
+ then,
+ else_sp,
+ outer,
+ semicolon,
+ opt_suggest_box_span,
+ }) => {
err.span_label(then, "expected because of this");
if let Some(sp) = outer {
err.span_label(sp, "`if` and `else` have incompatible types");
Applicability::MachineApplicable,
);
}
+ if let Some(ret_sp) = opt_suggest_box_span {
+ self.suggest_boxing_for_return_impl_trait(
+ err,
+ ret_sp,
+ vec![then, else_sp].into_iter(),
+ );
+ }
}
_ => (),
}
}
+ fn suggest_boxing_for_return_impl_trait(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ return_sp: Span,
+ arm_spans: impl Iterator<Item = Span>,
+ ) {
+ err.multipart_suggestion(
+ "you could change the return type to be a boxed trait object",
+ vec![
+ (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
+ (return_sp.shrink_to_hi(), ">".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ let sugg = arm_spans
+ .flat_map(|sp| {
+ vec![
+ (sp.shrink_to_lo(), "Box::new(".to_string()),
+ (sp.shrink_to_hi(), ")".to_string()),
+ ]
+ .into_iter()
+ })
+ .collect::<Vec<_>>();
+ err.multipart_suggestion(
+ "if you change the return type to expect trait objects, box the returned expressions",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ }
+
/// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value`
/// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and
/// populate `other_value` with `other_ty`.
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat};
use rustc_middle::hir::map::Map;
+use rustc_middle::infer::unify_key::ConstVariableOriginKind;
use rustc_middle::ty::print::Print;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_middle::ty::{self, DefIdTree, InferConst, Ty};
use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::kw;
use rustc_span::Span;
local_visitor.visit_expr(expr);
}
+ let mut param_name = None;
+ let span = if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val {
+ let origin = self.inner.borrow_mut().const_unification_table().probe_value(vid).origin;
+ if let ConstVariableOriginKind::ConstParameterDefinition(param) = origin.kind {
+ param_name = Some(param);
+ }
+ origin.span
+ } else {
+ local_visitor.target_span
+ };
+
let error_code = error_code.into();
- let mut err = self.tcx.sess.struct_span_err_with_code(
- local_visitor.target_span,
- "type annotations needed",
- error_code,
- );
+ let mut err =
+ self.tcx.sess.struct_span_err_with_code(span, "type annotations needed", error_code);
- err.note("unable to infer the value of a const parameter");
+ if let Some(param_name) = param_name {
+ err.note(&format!("cannot infer the value of the const parameter `{}`", param_name));
+ } else {
+ err.note("unable to infer the value of a const parameter");
+ }
err
}
use rustc_span::symbol::sym;
declare_lint! {
+ /// The `array_into_iter` lint detects calling `into_iter` on arrays.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # #![allow(unused)]
+ /// [1, 2, 3].into_iter().for_each(|n| { *n; });
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// In the future, it is planned to add an `IntoIter` implementation for
+ /// arrays such that it will iterate over *values* of the array instead of
+ /// references. Due to how method resolution works, this will change
+ /// existing code that uses `into_iter` on arrays. The solution to avoid
+ /// this warning is to use `iter()` instead of `into_iter()`.
+ ///
+ /// This is a [future-incompatible] lint to transition this to a hard error
+ /// in the future. See [issue #66145] for more details and a more thorough
+ /// description of the lint.
+ ///
+ /// [issue #66145]: https://github.com/rust-lang/rust/issues/66145
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub ARRAY_INTO_ITER,
Warn,
"detects calling `into_iter` on arrays",
pub use rustc_session::lint::builtin::*;
declare_lint! {
+ /// The `while_true` lint detects `while true { }`.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,no_run
+ /// while true {
+ ///
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// `while true` should be replaced with `loop`. A `loop` expression is
+ /// the preferred way to write an infinite loop because it more directly
+ /// expresses the intent of the loop.
WHILE_TRUE,
Warn,
"suggest using `loop { }` instead of `while true { }`"
}
declare_lint! {
+ /// The `box_pointers` lints use of the Box type.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(box_pointers)]
+ /// struct Foo {
+ /// x: Box<isize>,
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// This lint is mostly historical, and not particularly useful. `Box<T>`
+ /// used to be built into the language, and the only way to do heap
+ /// allocation. Today's Rust can call into other allocators, etc.
BOX_POINTERS,
Allow,
"use of owned (Box type) heap memory"
}
declare_lint! {
+ /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }`
+ /// instead of `Struct { x }` in a pattern.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// struct Point {
+ /// x: i32,
+ /// y: i32,
+ /// }
+ ///
+ ///
+ /// fn main() {
+ /// let p = Point {
+ /// x: 5,
+ /// y: 5,
+ /// };
+ ///
+ /// match p {
+ /// Point { x: x, y: y } => (),
+ /// }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The preferred style is to avoid the repetition of specifying both the
+ /// field name and the binding name if both identifiers are the same.
NON_SHORTHAND_FIELD_PATTERNS,
Warn,
"using `Struct { x: x }` instead of `Struct { x }` in a pattern"
}
declare_lint! {
+ /// The `unsafe_code` lint catches usage of `unsafe` code.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(unsafe_code)]
+ /// fn main() {
+ /// unsafe {
+ ///
+ /// }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// This lint is intended to restrict the usage of `unsafe`, which can be
+ /// difficult to use correctly.
UNSAFE_CODE,
Allow,
"usage of `unsafe` code"
}
declare_lint! {
+ /// The `missing_docs` lint detects missing documentation for public items.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(missing_docs)]
+ /// pub fn foo() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// This lint is intended to ensure that a library is well-documented.
+ /// Items without documentation can be difficult for users to understand
+ /// how to use properly.
+ ///
+ /// This lint is "allow" by default because it can be noisy, and not all
+ /// projects may want to enforce everything to be documented.
pub MISSING_DOCS,
Allow,
"detects missing documentation for public members",
}
declare_lint! {
+ /// The `missing_copy_implementations` lint detects potentially-forgotten
+ /// implementations of [`Copy`].
+ ///
+ /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(missing_copy_implementations)]
+ /// pub struct Foo {
+ /// pub field: i32
+ /// }
+ /// # fn main() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Historically (before 1.0), types were automatically marked as `Copy`
+ /// if possible. This was changed so that it required an explicit opt-in
+ /// by implementing the `Copy` trait. As part of this change, a lint was
+ /// added to alert if a copyable type was not marked `Copy`.
+ ///
+ /// This lint is "allow" by default because this code isn't bad; it is
+ /// common to write newtypes like this specifically so that a `Copy` type
+ /// is no longer `Copy`. `Copy` types can result in unintended copies of
+ /// large data which can impact performance.
pub MISSING_COPY_IMPLEMENTATIONS,
Allow,
"detects potentially-forgotten implementations of `Copy`"
}
declare_lint! {
+ /// The `missing_debug_implementations` lint detects missing
+ /// implementations of [`fmt::Debug`].
+ ///
+ /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(missing_debug_implementations)]
+ /// pub struct Foo;
+ /// # fn main() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Having a `Debug` implementation on all types can assist with
+ /// debugging, as it provides a convenient way to format and display a
+ /// value. Using the `#[derive(Debug)]` attribute will automatically
+ /// generate a typical implementation, or a custom implementation can be
+ /// added by manually implementing the `Debug` trait.
+ ///
+ /// This lint is "allow" by default because adding `Debug` to all types can
+ /// have a negative impact on compile time and code size. It also requires
+ /// boilerplate to be added to every type, which can be an impediment.
MISSING_DEBUG_IMPLEMENTATIONS,
Allow,
"detects missing implementations of Debug"
}
declare_lint! {
+ /// The `anonymous_parameters` lint detects anonymous parameters in trait
+ /// definitions.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,edition2015,compile_fail
+ /// #![deny(anonymous_parameters)]
+ /// // edition 2015
+ /// pub trait Foo {
+ /// fn foo(usize);
+ /// }
+ /// fn main() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// This syntax is mostly a historical accident, and can be worked around
+ /// quite easily by adding an `_` pattern or a descriptive identifier:
+ ///
+ /// ```rust
+ /// trait Foo {
+ /// fn foo(_: usize);
+ /// }
+ /// ```
+ ///
+ /// This syntax is now a hard error in the 2018 edition. In the 2015
+ /// edition, this lint is "allow" by default, because the old code is
+ /// still valid, and warning for all old code can be noisy. This lint
+ /// enables the [`cargo fix`] tool with the `--edition` flag to
+ /// automatically transition old code from the 2015 edition to 2018. The
+ /// tool will switch this lint to "warn" and will automatically apply the
+ /// suggested fix from the compiler (which is to add `_` to each
+ /// parameter). This provides a completely automated way to update old
+ /// code for a new edition. See [issue #41686] for more details.
+ ///
+ /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686
+ /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
pub ANONYMOUS_PARAMETERS,
Allow,
"detects anonymous parameters",
}
declare_lint! {
+ /// The `no_mangle_const_items` lint detects any `const` items with the
+ /// [`no_mangle` attribute].
+ ///
+ /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #[no_mangle]
+ /// const FOO: i32 = 5;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Constants do not have their symbols exported, and therefore, this
+ /// probably means you meant to use a [`static`], not a [`const`].
+ ///
+ /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
+ /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html
NO_MANGLE_CONST_ITEMS,
Deny,
"const items will not have their symbols exported"
}
declare_lint! {
+ /// The `no_mangle_generic_items` lint detects generic items that must be
+ /// mangled.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #[no_mangle]
+ /// fn foo<T>(t: T) {
+ ///
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// An function with generics must have its symbol mangled to accommodate
+ /// the generic parameter. The [`no_mangle` attribute] has no effect in
+ /// this situation, and should be removed.
+ ///
+ /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
NO_MANGLE_GENERIC_ITEMS,
Warn,
"generic items must be mangled"
}
declare_lint! {
+ /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
+ /// T` because it is [undefined behavior].
+ ///
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// unsafe {
+ /// let y = std::mem::transmute::<&i32, &mut i32>(&5);
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Certain assumptions are made about aliasing of data, and this transmute
+ /// violates those assumptions. Consider using [`UnsafeCell`] instead.
+ ///
+ /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
MUTABLE_TRANSMUTES,
Deny,
"mutating transmuted &mut T from &T may cause undefined behavior"
}
declare_lint! {
+ /// The `unstable_features` is deprecated and should no longer be used.
UNSTABLE_FEATURES,
Allow,
"enabling unstable features (deprecated. do not use)"
}
declare_lint! {
+ /// The `unreachable_pub` lint triggers for `pub` items not reachable from
+ /// the crate root.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(unreachable_pub)]
+ /// mod foo {
+ /// pub mod bar {
+ ///
+ /// }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// A bare `pub` visibility may be misleading if the item is not actually
+ /// publicly exported from the crate. The `pub(crate)` visibility is
+ /// recommended to be used instead, which more clearly expresses the intent
+ /// that the item is only visible within its own crate.
+ ///
+ /// This lint is "allow" by default because it will trigger for a large
+ /// amount existing Rust code, and has some false-positives. Eventually it
+ /// is desired for this to become warn-by-default.
pub UNREACHABLE_PUB,
Allow,
"`pub` items not reachable from crate root"
}
declare_lint! {
+ /// The `type_alias_bounds` lint detects bounds in type aliases.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// type SendVec<T: Send> = Vec<T>;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The trait bounds in a type alias are currently ignored, and should not
+ /// be included to avoid confusion. This was previously allowed
+ /// unintentionally; this may become a hard error in the future.
TYPE_ALIAS_BOUNDS,
Warn,
"bounds in type aliases are not enforced"
}
declare_lint! {
+ /// The `trivial_bounds` lint detects trait bounds that don't depend on
+ /// any type parameters.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![feature(trivial_bounds)]
+ /// pub struct A where i32: Copy;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Usually you would not write a trait bound that you know is always
+ /// true, or never true. However, when using macros, the macro may not
+ /// know whether or not the constraint would hold or not at the time when
+ /// generating the code. Currently, the compiler does not alert you if the
+ /// constraint is always true, and generates an error if it is never true.
+ /// The `trivial_bounds` feature changes this to be a warning in both
+ /// cases, giving macros more freedom and flexibility to generate code,
+ /// while still providing a signal when writing non-macro code that
+ /// something is amiss.
+ ///
+ /// See [RFC 2056] for more details. This feature is currently only
+ /// available on the nightly channel, see [tracking issue #48214].
+ ///
+ /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
+ /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
TRIVIAL_BOUNDS,
Warn,
"these bounds don't depend on an type parameters"
);
declare_lint! {
+ /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
+ /// pattern], which is deprecated.
+ ///
+ /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x = 123;
+ /// match x {
+ /// 0...100 => {}
+ /// _ => {}
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The `...` range pattern syntax was changed to `..=` to avoid potential
+ /// confusion with the [`..` range expression]. Use the new form instead.
+ ///
+ /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
Warn,
"`...` range patterns are deprecated"
}
declare_lint! {
+ /// The `unnameable_test_items` lint detects [`#[test]`][test] functions
+ /// that are not able to be run by the test harness because they are in a
+ /// position where they are not nameable.
+ ///
+ /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
+ ///
+ /// ### Example
+ ///
+ /// ```rust,test
+ /// fn main() {
+ /// #[test]
+ /// fn foo() {
+ /// // This test will not fail because it does not run.
+ /// assert_eq!(1, 2);
+ /// }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// In order for the test harness to run a test, the test function must be
+ /// located in a position where it can be accessed from the crate root.
+ /// This generally means it must be defined in a module, and not anywhere
+ /// else such as inside another function. The compiler previously allowed
+ /// this without an error, so a lint was added as an alert that a test is
+ /// not being used. Whether or not this should be allowed has not yet been
+ /// decided, see [RFC 2471] and [issue #36629].
+ ///
+ /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
+ /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
UNNAMEABLE_TEST_ITEMS,
Warn,
"detects an item that cannot be named being marked as `#[test_case]`",
}
declare_lint! {
+ /// The `keyword_idents` lint detects edition keywords being used as an
+ /// identifier.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,edition2015,compile_fail
+ /// #![deny(keyword_idents)]
+ /// // edition 2015
+ /// fn dyn() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Rust [editions] allow the language to evolve without breaking
+ /// backwards compatibility. This lint catches code that uses new keywords
+ /// that are added to the language that are used as identifiers (such as a
+ /// variable name, function name, etc.). If you switch the compiler to a
+ /// new edition without updating the code, then it will fail to compile if
+ /// you are using a new keyword as an identifier.
+ ///
+ /// You can manually change the identifiers to a non-keyword, or use a
+ /// [raw identifier], for example `r#dyn`, to transition to a new edition.
+ ///
+ /// This lint solves the problem automatically. It is "allow" by default
+ /// because the code is perfectly valid in older editions. The [`cargo
+ /// fix`] tool with the `--edition` flag will switch this lint to "warn"
+ /// and automatically apply the suggested fix from the compiler (which is
+ /// to use a raw identifier). This provides a completely automated way to
+ /// update old code for a new edition.
+ ///
+ /// [editions]: https://doc.rust-lang.org/edition-guide/
+ /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
+ /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
pub KEYWORD_IDENTS,
Allow,
"detects edition keywords being used as an identifier",
}
declare_lint! {
+ /// The `incomplete_features` lint detects unstable features enabled with
+ /// the [`feature` attribute] that may function improperly in some or all
+ /// cases.
+ ///
+ /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![feature(generic_associated_types)]
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Although it is encouraged for people to experiment with unstable
+ /// features, some of them are known to be incomplete or faulty. This lint
+ /// is a signal that the feature has not yet been finished, and you may
+ /// experience problems with it.
pub INCOMPLETE_FEATURES,
Warn,
"incomplete features that may function improperly in some or all cases"
}
declare_lint! {
+ /// The `invalid_value` lint detects creating a value that is not valid,
+ /// such as a NULL reference.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,no_run
+ /// # #![allow(unused)]
+ /// unsafe {
+ /// let x: &'static i32 = std::mem::zeroed();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// In some situations the compiler can detect that the code is creating
+ /// an invalid value, which should be avoided.
+ ///
+ /// In particular, this lint will check for improper use of
+ /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
+ /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
+ /// lint should provide extra information to indicate what the problem is
+ /// and a possible solution.
+ ///
+ /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
+ /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
+ /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
+ /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
pub INVALID_VALUE,
Warn,
"an invalid value is being created (such as a NULL reference)"
}
declare_lint! {
+ /// The `clashing_extern_declarations` lint detects when an `extern fn`
+ /// has been declared with the same name but different types.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// mod m {
+ /// extern "C" {
+ /// fn foo();
+ /// }
+ /// }
+ ///
+ /// extern "C" {
+ /// fn foo(_: u32);
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Because two symbols of the same name cannot be resolved to two
+ /// different functions at link time, and one function cannot possibly
+ /// have two types, a clashing extern declaration is almost certainly a
+ /// mistake. Check to make sure that the `extern` definitions are correct
+ /// and equivalent, and possibly consider unifying them in one location.
+ ///
+ /// This lint does not run between crates because a project may have
+ /// dependencies which both rely on the same extern function, but declare
+ /// it in a different (but valid) way. For example, they may both declare
+ /// an opaque type for one or more of the arguments (which would end up
+ /// distinct types), or use types that are valid conversions in the
+ /// language the `extern fn` is defined in. In these cases, the compiler
+ /// can't say that the clashing declaration is incorrect.
pub CLASHING_EXTERN_DECLARATIONS,
Warn,
"detects when an extern fn has been declared with the same name but different types"
use rustc_span::symbol::Symbol;
declare_lint! {
+ /// The `non_ascii_idents` lint detects non-ASCII identifiers.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// # #![allow(unused)]
+ /// #![feature(non_ascii_idents)]
+ /// #![deny(non_ascii_idents)]
+ /// fn main() {
+ /// let föö = 1;
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Currently on stable Rust, identifiers must contain ASCII characters.
+ /// The [`non_ascii_idents`] nightly-only feature allows identifiers to
+ /// contain non-ASCII characters. This lint allows projects that wish to
+ /// retain the limit of only using ASCII characters to switch this lint to
+ /// "forbid" (for example to ease collaboration or for security reasons).
+ /// See [RFC 2457] for more details.
+ ///
+ /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
+ /// [RFC 2457]: https://github.com/rust-lang/rfcs/blob/master/text/2457-non-ascii-idents.md
pub NON_ASCII_IDENTS,
Allow,
"detects non-ASCII identifiers",
}
declare_lint! {
+ /// The `uncommon_codepoints` lint detects uncommon Unicode codepoints in
+ /// identifiers.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # #![allow(unused)]
+ /// #![feature(non_ascii_idents)]
+ /// const µ: f64 = 0.000001;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// With the [`non_ascii_idents`] nightly-only feature enabled,
+ /// identifiers are allowed to use non-ASCII characters. This lint warns
+ /// about using characters which are not commonly used, and may cause
+ /// visual confusion.
+ ///
+ /// This lint is triggered by identifiers that contain a codepoint that is
+ /// not part of the set of "Allowed" codepoints as described by [Unicode®
+ /// Technical Standard #39 Unicode Security Mechanisms Section 3.1 General
+ /// Security Profile for Identifiers][TR39Allowed].
+ ///
+ /// Note that the set of uncommon codepoints may change over time. Beware
+ /// that if you "forbid" this lint that existing code may fail in the
+ /// future.
+ ///
+ /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
+ /// [TR39Allowed]: https://www.unicode.org/reports/tr39/#General_Security_Profile
pub UNCOMMON_CODEPOINTS,
Warn,
"detects uncommon Unicode codepoints in identifiers",
}
declare_lint! {
+ /// The `confusable_idents` lint detects visually confusable pairs between
+ /// identifiers.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![feature(non_ascii_idents)]
+ ///
+ /// // Latin Capital Letter E With Caron
+ /// pub const Ě: i32 = 1;
+ /// // Latin Capital Letter E With Breve
+ /// pub const Ĕ: i32 = 2;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// With the [`non_ascii_idents`] nightly-only feature enabled,
+ /// identifiers are allowed to use non-ASCII characters. This lint warns
+ /// when different identifiers may appear visually similar, which can
+ /// cause confusion.
+ ///
+ /// The confusable detection algorithm is based on [Unicode® Technical
+ /// Standard #39 Unicode Security Mechanisms Section 4 Confusable
+ /// Detection][TR39Confusable]. For every distinct identifier X execute
+ /// the function `skeleton(X)`. If there exist two distinct identifiers X
+ /// and Y in the same crate where `skeleton(X) = skeleton(Y)` report it.
+ /// The compiler uses the same mechanism to check if an identifier is too
+ /// similar to a keyword.
+ ///
+ /// Note that the set of confusable characters may change over time.
+ /// Beware that if you "forbid" this lint that existing code may fail in
+ /// the future.
+ ///
+ /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
+ /// [TR39Confusable]: https://www.unicode.org/reports/tr39/#Confusable_Detection
pub CONFUSABLE_IDENTS,
Warn,
"detects visually confusable pairs between identifiers",
}
declare_lint! {
+ /// The `mixed_script_confusables` lint detects visually confusable
+ /// characters in identifiers between different [scripts].
+ ///
+ /// [scripts]: https://en.wikipedia.org/wiki/Script_(Unicode)
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![feature(non_ascii_idents)]
+ ///
+ /// // The Japanese katakana character エ can be confused with the Han character 工.
+ /// const エ: &'static str = "アイウ";
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// With the [`non_ascii_idents`] nightly-only feature enabled,
+ /// identifiers are allowed to use non-ASCII characters. This lint warns
+ /// when characters between different scripts may appear visually similar,
+ /// which can cause confusion.
+ ///
+ /// If the crate contains other identifiers in the same script that have
+ /// non-confusable characters, then this lint will *not* be issued. For
+ /// example, if the example given above has another identifier with
+ /// katakana characters (such as `let カタカナ = 123;`), then this indicates
+ /// that you are intentionally using katakana, and it will not warn about
+ /// it.
+ ///
+ /// Note that the set of confusable characters may change over time.
+ /// Beware that if you "forbid" this lint that existing code may fail in
+ /// the future.
+ ///
+ /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
pub MIXED_SCRIPT_CONFUSABLES,
Warn,
"detects Unicode scripts whose mixed script confusables codepoints are solely used",
}
}
- ch_list.sort();
+ // We sort primitive chars here and can use unstable sort
+ ch_list.sort_unstable();
ch_list.dedup();
lint_reports.insert((sp, ch_list), augment_script_set);
}
}
declare_lint! {
+ /// The `non_camel_case_types` lint detects types, variants, traits and
+ /// type parameters that don't have camel case names.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// struct my_struct;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The preferred style for these identifiers is to use "camel case", such
+ /// as `MyStruct`, where the first letter should not be lowercase, and
+ /// should not use underscores between letters. Underscores are allowed at
+ /// the beginning and end of the identifier, as well as between
+ /// non-letters (such as `X86_64`).
pub NON_CAMEL_CASE_TYPES,
Warn,
"types, variants, traits and type parameters should have camel case names"
}
declare_lint! {
+ /// The `non_snake_case` lint detects variables, methods, functions,
+ /// lifetime parameters and modules that don't have snake case names.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let MY_VALUE = 5;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The preferred style for these identifiers is to use "snake case",
+ /// where all the characters are in lowercase, with words separated with a
+ /// single underscore, such as `my_value`.
pub NON_SNAKE_CASE,
Warn,
"variables, methods, functions, lifetime parameters and modules should have snake case names"
}
declare_lint! {
+ /// The `non_upper_case_globals` lint detects static items that don't have
+ /// uppercase identifiers.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// static max_points: i32 = 5;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The preferred style is for static item names to use all uppercase
+ /// letters such as `MAX_POINTS`.
pub NON_UPPER_CASE_GLOBALS,
Warn,
"static constants should have uppercase identifiers"
use rustc_span::Span;
declare_lint! {
+ /// The `redundant_semicolons` lint detects unnecessary trailing
+ /// semicolons.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let _ = 123;;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Extra semicolons are not needed, and may be removed to avoid confusion
+ /// and visual clutter.
pub REDUNDANT_SEMICOLONS,
Warn,
"detects unnecessary trailing semicolons"
use tracing::debug;
declare_lint! {
+ /// The `unused_comparisons` lint detects comparisons made useless by
+ /// limits of the types involved.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// fn foo(x: u8) {
+ /// x >= 0;
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// A useless comparison may indicate a mistake, and should be fixed or
+ /// removed.
UNUSED_COMPARISONS,
Warn,
"comparisons made useless by limits of the types involved"
}
declare_lint! {
+ /// The `overflowing_literals` lint detects literal out of range for its
+ /// type.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// let x: u8 = 1000;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// It is usually a mistake to use a literal that overflows the type where
+ /// it is used. Either use a literal that is within range, or change the
+ /// type to be within the range of the literal.
OVERFLOWING_LITERALS,
Deny,
"literal out of range for its type"
}
declare_lint! {
+ /// The `variant_size_differences` lint detects enums with widely varying
+ /// variant sizes.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(variant_size_differences)]
+ /// enum En {
+ /// V0(u8),
+ /// VBig([u8; 1024]),
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// It can be a mistake to add a variant to an enum that is much larger
+ /// than the other variants, bloating the overall size required for all
+ /// variants. This can impact performance and memory usage. This is
+ /// triggered if one variant is more than 3 times larger than the
+ /// second-largest variant.
+ ///
+ /// Consider placing the large variant's contents on the heap (for example
+ /// via [`Box`]) to keep the overall size of the enum itself down.
+ ///
+ /// This lint is "allow" by default because it can be noisy, and may not be
+ /// an actual problem. Decisions about this should be guided with
+ /// profiling and benchmarking.
+ ///
+ /// [`Box`]: https://doc.rust-lang.org/std/boxed/index.html
VARIANT_SIZE_DIFFERENCES,
Allow,
"detects enums with widely varying variant sizes"
}
declare_lint! {
+ /// The `improper_ctypes` lint detects incorrect use of types in foreign
+ /// modules.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// extern "C" {
+ /// static STATIC: String;
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The compiler has several checks to verify that types used in `extern`
+ /// blocks are safe and follow certain rules to ensure proper
+ /// compatibility with the foreign interfaces. This lint is issued when it
+ /// detects a probable mistake in a definition. The lint usually should
+ /// provide a description of the issue, along with possibly a hint on how
+ /// to resolve it.
IMPROPER_CTYPES,
Warn,
"proper use of libc types in foreign modules"
declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
declare_lint! {
+ /// The `improper_ctypes_definitions` lint detects incorrect use of
+ /// [`extern` function] definitions.
+ ///
+ /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # #![allow(unused)]
+ /// pub extern "C" fn str_type(p: &str) { }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// There are many parameter and return types that may be specified in an
+ /// `extern` function that are not compatible with the given ABI. This
+ /// lint is an alert that these types should not be used. The lint usually
+ /// should provide a description of the issue, along with possibly a hint
+ /// on how to resolve it.
IMPROPER_CTYPES_DEFINITIONS,
Warn,
"proper use of libc types in foreign item definitions"
use tracing::debug;
declare_lint! {
+ /// The `unused_must_use` lint detects unused result of a type flagged as
+ /// `#[must_use]`.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// fn returns_result() -> Result<(), ()> {
+ /// Ok(())
+ /// }
+ ///
+ /// fn main() {
+ /// returns_result();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The `#[must_use]` attribute is an indicator that it is a mistake to
+ /// ignore the value. See [the reference] for more details.
+ ///
+ /// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
pub UNUSED_MUST_USE,
Warn,
"unused result of a type flagged as `#[must_use]`",
}
declare_lint! {
+ /// The `unused_results` lint checks for the unused result of an
+ /// expression in a statement.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(unused_results)]
+ /// fn foo<T>() -> T { panic!() }
+ ///
+ /// fn main() {
+ /// foo::<usize>();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Ignoring the return value of a function may indicate a mistake. In
+ /// cases were it is almost certain that the result should be used, it is
+ /// recommended to annotate the function with the [`must_use` attribute].
+ /// Failure to use such a return value will trigger the [`unused_must_use`
+ /// lint] which is warn-by-default. The `unused_results` lint is
+ /// essentially the same, but triggers for *all* return values.
+ ///
+ /// This lint is "allow" by default because it can be noisy, and may not be
+ /// an actual problem. For example, calling the `remove` method of a `Vec`
+ /// or `HashMap` returns the previous value, which you may not care about.
+ /// Using this lint would require explicitly ignoring or discarding such
+ /// values.
+ ///
+ /// [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
+ /// [`unused_must_use` lint]: warn-by-default.html#unused-must-use
pub UNUSED_RESULTS,
Allow,
"unused result of an expression in a statement"
}
declare_lint! {
+ /// The `path_statements` lint detects path statements with no effect.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x = 42;
+ ///
+ /// x;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// It is usually a mistake to have a statement that has no effect.
pub PATH_STATEMENTS,
Warn,
"path statements with no effect"
}
declare_lint! {
+ /// The `unused_parens` lint detects `if`, `match`, `while` and `return`
+ /// with parentheses; they do not need them.
+ ///
+ /// ### Examples
+ ///
+ /// ```rust
+ /// if(true) {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The parenthesis are not needed, and should be removed. This is the
+ /// preferred style for writing these expressions.
pub(super) UNUSED_PARENS,
Warn,
"`if`, `match`, `while` and `return` do not need parentheses"
}
declare_lint! {
+ /// The `unused_braces` lint detects unnecessary braces around an
+ /// expression.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// if { true } {
+ /// // ...
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The braces are not needed, and should be removed. This is the
+ /// preferred style for writing these expressions.
pub(super) UNUSED_BRACES,
Warn,
"unnecessary braces around an expression"
}
declare_lint! {
+ /// The `unused_import_braces` lint catches unnecessary braces around an
+ /// imported item.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(unused_import_braces)]
+ /// use test::{A};
+ ///
+ /// pub mod test {
+ /// pub struct A;
+ /// }
+ /// # fn main() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// If there is only a single item, then remove the braces (`use test::A;`
+ /// for example).
+ ///
+ /// This lint is "allow" by default because it is only enforcing a
+ /// stylistic choice.
UNUSED_IMPORT_BRACES,
Allow,
"unnecessary braces around an imported item"
}
declare_lint! {
+ /// The `unused_allocation` lint detects unnecessary allocations that can
+ /// be eliminated.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![feature(box_syntax)]
+ /// fn main() {
+ /// let a = (box [1,2,3]).len();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// When a `box` expression is immediately coerced to a reference, then
+ /// the allocation is unnecessary, and a reference (using `&` or `&mut`)
+ /// should be used instead to avoid the allocation.
pub(super) UNUSED_ALLOCATION,
Warn,
"detects unnecessary allocations that can be eliminated"
rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
+rustc_feature = { path = "../rustc_feature" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
rustc_target = { path = "../rustc_target" }
pub(super) struct EncodeContext<'a, 'tcx> {
opaque: opaque::Encoder,
tcx: TyCtxt<'tcx>,
+ feat: &'tcx rustc_feature::Features,
tables: TableBuilders<'tcx>,
fn encode_stability(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_stability({:?})", def_id);
- if let Some(stab) = self.tcx.lookup_stability(def_id) {
- record!(self.tables.stability[def_id] <- stab)
+
+ // The query lookup can take a measurable amount of time in crates with many items. Check if
+ // the stability attributes are even enabled before using their queries.
+ if self.feat.staged_api || self.tcx.sess.opts.debugging_opts.force_unstable_if_unmarked {
+ if let Some(stab) = self.tcx.lookup_stability(def_id) {
+ record!(self.tables.stability[def_id] <- stab)
+ }
}
}
fn encode_const_stability(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_const_stability({:?})", def_id);
- if let Some(stab) = self.tcx.lookup_const_stability(def_id) {
- record!(self.tables.const_stability[def_id] <- stab)
+
+ // The query lookup can take a measurable amount of time in crates with many items. Check if
+ // the stability attributes are even enabled before using their queries.
+ if self.feat.staged_api || self.tcx.sess.opts.debugging_opts.force_unstable_if_unmarked {
+ if let Some(stab) = self.tcx.lookup_const_stability(def_id) {
+ record!(self.tables.const_stability[def_id] <- stab)
+ }
}
}
let mut ecx = EncodeContext {
opaque: encoder,
tcx,
+ feat: tcx.features(),
tables: Default::default(),
lazy_state: LazyState::NoNode,
type_shorthands: Default::default(),
pub enum ConstVariableOriginKind {
MiscVariable,
ConstInference,
+ // FIXME(const_generics): Consider storing the `DefId` of the param here.
ConstParameterDefinition(Symbol),
SubstitutionPlaceholder,
}
/// Constants
///
/// Two constants are equal if they are the same constant. Note that
-/// this does not necessarily mean that they are "==" in Rust -- in
-/// particular one must be wary of `NaN`!
+/// this does not necessarily mean that they are `==` in Rust -- in
+/// particular, one must be wary of `NaN`!
#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)]
pub struct Constant<'tcx> {
pub prior_arms: Vec<Span>,
pub last_ty: Ty<'tcx>,
pub scrut_hir_id: hir::HirId,
+ pub opt_suggest_box_span: Option<Span>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct IfExpressionCause {
pub then: Span,
+ pub else_sp: Span,
pub outer: Option<Span>,
pub semicolon: Option<Span>,
+ pub opt_suggest_box_span: Option<Span>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_macros::HashStable;
+use rustc_span::Span;
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
pub enum PointerCast {
pub struct OverloadedDeref<'tcx> {
pub region: ty::Region<'tcx>,
pub mutbl: hir::Mutability,
+ /// The `Span` associated with the field access or method call
+ /// that triggered this overloaded deref.
+ pub span: Span,
}
impl<'tcx> OverloadedDeref<'tcx> {
use std::ops::{Bound, Deref};
use std::sync::Arc;
-/// A type that is not publicly constructable. This prevents people from making `TyKind::Error`
-/// except through `tcx.err*()`, which are in this module.
+/// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s
+/// except through the error-reporting functions on a [`tcx`][TyCtxt].
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
#[derive(TyEncodable, TyDecodable, HashStable)]
pub struct DelaySpanBugEmitted(());
// Suggestion:
// fn foo<T>(t: T) where T: Foo, T: Bar {... }
// - insert: `, T: Zar`
+ //
+ // Additionally, there may be no `where` clause whatsoever in the case that this was
+ // reached because the generic parameter has a default:
+ //
+ // Message:
+ // trait Foo<T=()> {... }
+ // - help: consider further restricting this type parameter with `where T: Zar`
+ //
+ // Suggestion:
+ // trait Foo<T=()> where T: Zar {... }
+ // - insert: `where T: Zar`
- let mut param_spans = Vec::new();
+ if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
+ && generics.where_clause.predicates.len() == 0
+ {
+ // Suggest a bound, but there is no existing `where` clause *and* the type param has a
+ // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
+ err.span_suggestion_verbose(
+ generics.where_clause.tail_span_for_suggestion(),
+ &msg_restrict_type_further,
+ format!(" where {}: {}", param_name, constraint),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ let mut param_spans = Vec::new();
- for predicate in generics.where_clause.predicates {
- if let WherePredicate::BoundPredicate(WhereBoundPredicate {
- span, bounded_ty, ..
- }) = predicate
- {
- if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
- if let Some(segment) = path.segments.first() {
- if segment.ident.to_string() == param_name {
- param_spans.push(span);
+ for predicate in generics.where_clause.predicates {
+ if let WherePredicate::BoundPredicate(WhereBoundPredicate {
+ span,
+ bounded_ty,
+ ..
+ }) = predicate
+ {
+ if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind {
+ if let Some(segment) = path.segments.first() {
+ if segment.ident.to_string() == param_name {
+ param_spans.push(span);
+ }
}
}
}
}
- }
- match ¶m_spans[..] {
- &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()),
- _ => {
- err.span_suggestion_verbose(
- generics.where_clause.tail_span_for_suggestion(),
- &msg_restrict_type_further,
- format!(", {}: {}", param_name, constraint),
- Applicability::MachineApplicable,
- );
+ match ¶m_spans[..] {
+ &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()),
+ _ => {
+ err.span_suggestion_verbose(
+ generics.where_clause.tail_span_for_suggestion(),
+ &msg_restrict_type_further,
+ format!(", {}: {}", param_name, constraint),
+ Applicability::MachineApplicable,
+ );
+ }
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> {
type Lifted = ty::adjustment::OverloadedDeref<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- tcx.lift(&self.region)
- .map(|region| ty::adjustment::OverloadedDeref { region, mutbl: self.mutbl })
+ tcx.lift(&self.region).map(|region| ty::adjustment::OverloadedDeref {
+ region,
+ mutbl: self.mutbl,
+ span: self.span,
+ })
}
}
/// particular, imagine a type like this:
///
/// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char)
- /// ^ ^ | | |
- /// | | | | |
- /// | +------------+ 0 | |
- /// | | |
- /// +--------------------------------+ 1 |
- /// | |
- /// +------------------------------------------+ 0
+ /// ^ ^ | | |
+ /// | | | | |
+ /// | +------------+ 0 | |
+ /// | | |
+ /// +----------------------------------+ 1 |
+ /// | |
+ /// +----------------------------------------------+ 0
///
/// In this type, there are two binders (the outer fn and the inner
/// fn). We need to be able to determine, for any given region, which
///
/// Returning true means the type is known to be sized. Returning
/// `false` means nothing -- could be sized, might not be.
+ ///
+ /// Note that we could never rely on the fact that a type such as `[_]` is
+ /// trivially `!Sized` because we could be in a type environment with a
+ /// bound such as `[_]: Copy`. A function with such a bound obviously never
+ /// can be called, but that doesn't mean it shouldn't typecheck. This is why
+ /// this method doesn't return `Option<bool>`.
pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool {
match self.kind() {
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
let span = use_spans.args_or_use();
let move_site_vec = self.get_moved_indexes(location, mpi);
- debug!("report_use_of_moved_or_uninitialized: move_site_vec={:?}", move_site_vec);
+ debug!(
+ "report_use_of_moved_or_uninitialized: move_site_vec={:?} use_spans={:?}",
+ move_site_vec, use_spans
+ );
let move_out_indices: Vec<_> =
move_site_vec.iter().map(|move_site| move_site.moi).collect();
);
}
}
+ // Deref::deref takes &self, which cannot cause a move
+ FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
}
} else {
err.span_label(
self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span, partial_str);
}
+ if let UseSpans::FnSelfUse {
+ kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty },
+ ..
+ } = use_spans
+ {
+ err.note(&format!(
+ "{} occurs due to deref coercion to `{}`",
+ desired_action.as_noun(),
+ deref_target_ty
+ ));
+
+ err.span_note(deref_target, "deref defined here");
+ }
+
if let Some((_, mut old_err)) =
self.move_error_reported.insert(move_out_indices, (used_place, err))
{
name: &str,
borrow: &BorrowData<'tcx>,
drop_span: Span,
- borrow_spans: UseSpans,
+ borrow_spans: UseSpans<'tcx>,
explanation: BorrowExplanation,
) -> DiagnosticBuilder<'cx> {
debug!(
location: Location,
borrow: &BorrowData<'tcx>,
drop_span: Span,
- borrow_spans: UseSpans,
+ borrow_spans: UseSpans<'tcx>,
proper_span: Span,
explanation: BorrowExplanation,
) -> DiagnosticBuilder<'cx> {
fn report_escaping_closure_capture(
&mut self,
- use_span: UseSpans,
+ use_span: UseSpans<'tcx>,
var_span: Span,
fr_name: &RegionName,
category: ConstraintCategory,
fn later_use_kind(
&self,
borrow: &BorrowData<'tcx>,
- use_spans: UseSpans,
+ use_spans: UseSpans<'tcx>,
location: Location,
) -> (LaterUseKind, Span) {
match use_spans {
PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
};
use rustc_middle::ty::print::Print;
-use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
use rustc_span::{
hygiene::{DesugaringKind, ForLoopLoc},
symbol::sym,
/// The span(s) associated to a use of a place.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(super) enum UseSpans {
+pub(super) enum UseSpans<'tcx> {
/// The access is caused by capturing a variable for a closure.
ClosureUse {
/// This is true if the captured variable was from a generator.
fn_call_span: Span,
/// The definition span of the method being called
fn_span: Span,
- kind: FnSelfUseKind,
+ kind: FnSelfUseKind<'tcx>,
},
/// This access is caused by a `match` or `if let` pattern.
PatUse(Span),
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(super) enum FnSelfUseKind {
+pub(super) enum FnSelfUseKind<'tcx> {
/// A normal method call of the form `receiver.foo(a, b, c)`
Normal { self_arg: Ident, implicit_into_iter: bool },
/// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
FnOnceCall,
/// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
Operator { self_arg: Ident },
+ DerefCoercion {
+ /// The `Span` of the `Target` associated type
+ /// in the `Deref` impl we are using.
+ deref_target: Span,
+ /// The type `T::Deref` we are dereferencing to
+ deref_target_ty: Ty<'tcx>,
+ },
}
-impl UseSpans {
+impl UseSpans<'_> {
pub(super) fn args_or_use(self) -> Span {
match self {
UseSpans::ClosureUse { args_span: span, .. }
| UseSpans::PatUse(span)
- | UseSpans::FnSelfUse { var_span: span, .. }
| UseSpans::OtherUse(span) => span,
+ UseSpans::FnSelfUse {
+ fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
+ } => fn_call_span,
+ UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
match self {
UseSpans::ClosureUse { var_span: span, .. }
| UseSpans::PatUse(span)
- | UseSpans::FnSelfUse { var_span: span, .. }
| UseSpans::OtherUse(span) => span,
+ UseSpans::FnSelfUse {
+ fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
+ } => fn_call_span,
+ UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
&self,
moved_place: PlaceRef<'tcx>, // Could also be an upvar.
location: Location,
- ) -> UseSpans {
+ ) -> UseSpans<'tcx> {
use self::UseSpans::*;
let stmt = match self.body[location.block].statements.get(location.statement_index) {
kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
}) = &self.body[location.block].terminator
{
- let method_did = if let Some(method_did) =
+ let (method_did, method_substs) = if let Some(info) =
crate::util::find_self_call(self.infcx.tcx, &self.body, target_temp, location.block)
{
- method_did
+ info
} else {
return normal_ret;
};
let tcx = self.infcx.tcx;
-
let parent = tcx.parent(method_did);
let is_fn_once = parent == tcx.lang_items().fn_once_trait();
let is_operator = !from_hir_call
&& parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
+ let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
let fn_call_span = *fn_span;
let self_arg = tcx.fn_arg_names(method_did)[0];
+ debug!(
+ "terminator = {:?} from_hir_call={:?}",
+ self.body[location.block].terminator, from_hir_call
+ );
+
+ // Check for a 'special' use of 'self' -
+ // an FnOnce call, an operator (e.g. `<<`), or a
+ // deref coercion.
let kind = if is_fn_once {
- FnSelfUseKind::FnOnceCall
+ Some(FnSelfUseKind::FnOnceCall)
} else if is_operator {
- FnSelfUseKind::Operator { self_arg }
+ Some(FnSelfUseKind::Operator { self_arg })
+ } else if is_deref {
+ let deref_target =
+ tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
+ Instance::resolve(tcx, self.param_env, deref_target, method_substs)
+ .transpose()
+ });
+ if let Some(Ok(instance)) = deref_target {
+ let deref_target_ty = instance.ty(tcx, self.param_env);
+ Some(FnSelfUseKind::DerefCoercion {
+ deref_target: tcx.def_span(instance.def_id()),
+ deref_target_ty,
+ })
+ } else {
+ None
+ }
} else {
+ None
+ };
+
+ let kind = kind.unwrap_or_else(|| {
+ // This isn't a 'special' use of `self`
debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
let implicit_into_iter = matches!(
fn_call_span.desugaring_kind(),
Some(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
);
FnSelfUseKind::Normal { self_arg, implicit_into_iter }
- };
+ });
return FnSelfUse {
var_span: stmt.source_info.span,
/// and its usage of the local assigned at `location`.
/// This is done by searching in statements succeeding `location`
/// and originating from `maybe_closure_span`.
- pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans {
+ pub(super) fn borrow_spans(&self, use_span: Span, location: Location) -> UseSpans<'tcx> {
use self::UseSpans::*;
debug!("borrow_spans: use_span={:?} location={:?}", use_span, location);
/// Helper to retrieve span(s) of given borrow from the current MIR
/// representation
- pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans {
+ pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans<'tcx> {
let span = self.body.source_info(borrow.reserve_location).span;
self.borrow_spans(span, borrow.reserve_location)
}
// Everything that isn't from pattern matching.
OtherIllegalMove {
original_path: Place<'tcx>,
- use_spans: UseSpans,
+ use_spans: UseSpans<'tcx>,
kind: IllegalMoveOriginKind<'tcx>,
},
}
let (mut err, err_span) = {
let (span, use_spans, original_path, kind): (
Span,
- Option<UseSpans>,
+ Option<UseSpans<'tcx>>,
Place<'tcx>,
&IllegalMoveOriginKind<'_>,
) = match error {
move_place: Place<'tcx>,
deref_target_place: Place<'tcx>,
span: Span,
- use_spans: Option<UseSpans>,
+ use_spans: Option<UseSpans<'tcx>>,
) -> DiagnosticBuilder<'a> {
// Inspect the type of the content behind the
// borrow to provide feedback about why this
use rustc_middle::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, InstanceDef, RegionVid, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, ParamEnv, RegionVid, TyCtxt};
use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT};
use rustc_span::{Span, Symbol, DUMMY_SP};
if let Err((move_data, move_errors)) = move_data_results {
let mut promoted_mbcx = MirBorrowckCtxt {
infcx,
+ param_env,
body: promoted_body,
mir_def_id: def.did,
move_data: &move_data,
let mut mbcx = MirBorrowckCtxt {
infcx,
+ param_env,
body,
mir_def_id: def.did,
move_data: &mdpe.move_data,
crate struct MirBorrowckCtxt<'cx, 'tcx> {
crate infcx: &'cx InferCtxt<'cx, 'tcx>,
+ param_env: ParamEnv<'tcx>,
body: &'cx Body<'tcx>,
mir_def_id: LocalDefId,
move_data: &'cx MoveData<'tcx>,
use rustc_middle::ty::{self, DefIdTree, InstanceDef, TyCtxt};
use rustc_span::symbol::Symbol;
+use super::PartitioningCx;
use crate::monomorphize::collector::InliningMap;
use crate::monomorphize::partitioning::merging;
use crate::monomorphize::partitioning::{
impl<'tcx> Partitioner<'tcx> for DefaultPartitioning {
fn place_root_mono_items(
&mut self,
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
) -> PreInliningPartitioning<'tcx> {
let mut roots = FxHashSet::default();
let mut codegen_units = FxHashMap::default();
- let is_incremental_build = tcx.sess.opts.incremental.is_some();
+ let is_incremental_build = cx.tcx.sess.opts.incremental.is_some();
let mut internalization_candidates = FxHashSet::default();
// Determine if monomorphizations instantiated in this crate will be made
// available to downstream crates. This depends on whether we are in
// share-generics mode and whether the current crate can even have
// downstream crates.
- let export_generics = tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics();
+ let export_generics =
+ cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics();
- let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
+ let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
let cgu_name_cache = &mut FxHashMap::default();
for mono_item in mono_items {
- match mono_item.instantiation_mode(tcx) {
+ match mono_item.instantiation_mode(cx.tcx) {
InstantiationMode::GloballyShared { .. } => {}
InstantiationMode::LocalCopy => continue,
}
- let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item);
+ let characteristic_def_id = characteristic_def_id_of_mono_item(cx.tcx, mono_item);
let is_volatile = is_incremental_build && mono_item.is_generic_fn();
let codegen_unit_name = match characteristic_def_id {
Some(def_id) => compute_codegen_unit_name(
- tcx,
+ cx.tcx,
cgu_name_builder,
def_id,
is_volatile,
let mut can_be_internalized = true;
let (linkage, visibility) = mono_item_linkage_and_visibility(
- tcx,
+ cx.tcx,
&mono_item,
&mut can_be_internalized,
export_generics,
fn merge_codegen_units(
&mut self,
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
- target_cgu_count: usize,
) {
- merging::merge_codegen_units(tcx, initial_partitioning, target_cgu_count);
+ merging::merge_codegen_units(cx, initial_partitioning);
}
fn place_inlined_mono_items(
&mut self,
+ cx: &PartitioningCx<'_, 'tcx>,
initial_partitioning: PreInliningPartitioning<'tcx>,
- inlining_map: &InliningMap<'tcx>,
) -> PostInliningPartitioning<'tcx> {
let mut new_partitioning = Vec::new();
let mut mono_item_placements = FxHashMap::default();
// Collect all items that need to be available in this codegen unit.
let mut reachable = FxHashSet::default();
for root in old_codegen_unit.items().keys() {
- follow_inlining(*root, inlining_map, &mut reachable);
+ follow_inlining(*root, cx.inlining_map, &mut reachable);
}
let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name());
fn internalize_symbols(
&mut self,
- _tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
partitioning: &mut PostInliningPartitioning<'tcx>,
- inlining_map: &InliningMap<'tcx>,
) {
if partitioning.codegen_units.len() == 1 {
// Fast path for when there is only one codegen unit. In this case we
// Build a map from every monomorphization to all the monomorphizations that
// reference it.
let mut accessor_map: FxHashMap<MonoItem<'tcx>, Vec<MonoItem<'tcx>>> = Default::default();
- inlining_map.iter_accesses(|accessor, accessees| {
+ cx.inlining_map.iter_accesses(|accessor, accessees| {
for accessee in accessees {
accessor_map.entry(*accessee).or_default().push(accessor);
}
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder};
-use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::{Symbol, SymbolStr};
+use super::PartitioningCx;
use crate::monomorphize::partitioning::PreInliningPartitioning;
pub fn merge_codegen_units<'tcx>(
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
- target_cgu_count: usize,
) {
- assert!(target_cgu_count >= 1);
+ assert!(cx.target_cgu_count >= 1);
let codegen_units = &mut initial_partitioning.codegen_units;
// Note that at this point in time the `codegen_units` here may not be in a
codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name().as_str()])).collect();
// Merge the two smallest codegen units until the target size is reached.
- while codegen_units.len() > target_cgu_count {
+ while codegen_units.len() > cx.target_cgu_count {
// Sort small cgus to the back
codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate()));
let mut smallest = codegen_units.pop().unwrap();
);
}
- let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx);
+ let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
- if tcx.sess.opts.incremental.is_some() {
+ if cx.tcx.sess.opts.incremental.is_some() {
// If we are doing incremental compilation, we want CGU names to
// reflect the path of the source level module they correspond to.
// For CGUs that contain the code of multiple modules because of the
// Sort the names, so things are deterministic and easy to
// predict.
- cgu_contents.sort();
+
+ // We are sorting primitive &strs here so we can use unstable sort
+ cgu_contents.sort_unstable();
(current_cgu_name, cgu_contents.join("--"))
})
for cgu in codegen_units.iter_mut() {
if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) {
- if tcx.sess.opts.debugging_opts.human_readable_cgu_names {
+ if cx.tcx.sess.opts.debugging_opts.human_readable_cgu_names {
cgu.set_name(Symbol::intern(&new_cgu_name));
} else {
// If we don't require CGU names to be human-readable, we
use crate::monomorphize::collector::InliningMap;
use crate::monomorphize::collector::{self, MonoItemCollectionMode};
+pub struct PartitioningCx<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ target_cgu_count: usize,
+ inlining_map: &'a InliningMap<'tcx>,
+}
+
trait Partitioner<'tcx> {
fn place_root_mono_items(
&mut self,
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
) -> PreInliningPartitioning<'tcx>;
fn merge_codegen_units(
&mut self,
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
initial_partitioning: &mut PreInliningPartitioning<'tcx>,
- target_cgu_count: usize,
);
fn place_inlined_mono_items(
&mut self,
+ cx: &PartitioningCx<'_, 'tcx>,
initial_partitioning: PreInliningPartitioning<'tcx>,
- inlining_map: &InliningMap<'tcx>,
) -> PostInliningPartitioning<'tcx>;
fn internalize_symbols(
&mut self,
- tcx: TyCtxt<'tcx>,
+ cx: &PartitioningCx<'_, 'tcx>,
partitioning: &mut PostInliningPartitioning<'tcx>,
- inlining_map: &InliningMap<'tcx>,
);
}
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
let mut partitioner = get_partitioner(tcx);
+ let cx = &PartitioningCx { tcx, target_cgu_count: max_cgu_count, inlining_map };
// In the first step, we place all regular monomorphizations into their
// respective 'home' codegen unit. Regular monomorphizations are all
// functions and statics defined in the local crate.
let mut initial_partitioning = {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
- partitioner.place_root_mono_items(tcx, mono_items)
+ partitioner.place_root_mono_items(cx, mono_items)
};
initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
// Merge until we have at most `max_cgu_count` codegen units.
{
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
- partitioner.merge_codegen_units(tcx, &mut initial_partitioning, max_cgu_count);
+ partitioner.merge_codegen_units(cx, &mut initial_partitioning);
debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
}
// local functions the definition of which is marked with `#[inline]`.
let mut post_inlining = {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
- partitioner.place_inlined_mono_items(initial_partitioning, inlining_map)
+ partitioner.place_inlined_mono_items(cx, initial_partitioning)
};
post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx));
// more freedom to optimize.
if !tcx.sess.link_dead_code() {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
- partitioner.internalize_symbols(tcx, &mut post_inlining, inlining_map);
+ partitioner.internalize_symbols(cx, &mut post_inlining);
}
// Finally, sort by codegen unit name, so that we get deterministic results.
.note("each usage of a `const` item creates a new temporary")
.note("the mutable reference will refer to this temporary, not the original `const` item");
- if let Some(method_did) = method_did {
+ if let Some((method_did, _substs)) = method_did {
lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
}
let return_block = destination.1;
// Copy the arguments if needed.
- let args: Vec<_> = self.make_call_args(args, &callsite, caller_body);
+ let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, return_block);
let bb_len = caller_body.basic_blocks().len();
let mut integrator = Integrator {
args: Vec<Operand<'tcx>>,
callsite: &CallSite<'tcx>,
caller_body: &mut Body<'tcx>,
+ return_block: BasicBlock,
) -> Vec<Local> {
let tcx = self.tcx;
// and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
if tcx.is_closure(callsite.callee) {
let mut args = args.into_iter();
- let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
- let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
+ let self_ = self.create_temp_if_necessary(
+ args.next().unwrap(),
+ callsite,
+ caller_body,
+ return_block,
+ );
+ let tuple = self.create_temp_if_necessary(
+ args.next().unwrap(),
+ callsite,
+ caller_body,
+ return_block,
+ );
assert!(args.next().is_none());
let tuple = Place::from(tuple);
Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty()));
// Spill to a local to make e.g., `tmp0`.
- self.create_temp_if_necessary(tuple_field, callsite, caller_body)
+ self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block)
});
closure_ref_arg.chain(tuple_tmp_args).collect()
} else {
args.into_iter()
- .map(|a| self.create_temp_if_necessary(a, callsite, caller_body))
+ .map(|a| self.create_temp_if_necessary(a, callsite, caller_body, return_block))
.collect()
}
}
arg: Operand<'tcx>,
callsite: &CallSite<'tcx>,
caller_body: &mut Body<'tcx>,
+ return_block: BasicBlock,
) -> Local {
// FIXME: Analysis of the usage of the arguments to avoid
// unnecessary temporaries.
let arg_tmp = LocalDecl::new(ty, callsite.location.span);
let arg_tmp = caller_body.local_decls.push(arg_tmp);
- let stmt = Statement {
+ caller_body[callsite.bb].statements.push(Statement {
+ source_info: callsite.location,
+ kind: StatementKind::StorageLive(arg_tmp),
+ });
+ caller_body[callsite.bb].statements.push(Statement {
source_info: callsite.location,
kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)),
- };
- caller_body[callsite.bb].statements.push(stmt);
+ });
+ caller_body[return_block].statements.insert(
+ 0,
+ Statement { source_info: callsite.location, kind: StatementKind::StorageDead(arg_tmp) },
+ );
+
arg_tmp
}
}
}
}
}
-
- nop_stmts.sort();
+ // We sort primitive usize here so we can use unstable sort
+ nop_stmts.sort_unstable();
// Use one of the statements we're going to discard between the point
// where the storage location for the variant field becomes live and
use rustc_middle::mir::*;
+use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::DefId;
/// Checks if the specified `local` is used as the `self` prameter of a method call
/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is
/// returned.
-pub fn find_self_call(
- tcx: TyCtxt<'_>,
- body: &Body<'_>,
+pub fn find_self_call<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'tcx>,
local: Local,
block: BasicBlock,
-) -> Option<DefId> {
+) -> Option<(DefId, SubstsRef<'tcx>)> {
debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator);
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
&body[block].terminator
{
debug!("find_self_call: func={:?}", func);
if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func {
- if let ty::FnDef(def_id, _) = *ty.kind() {
+ if let ty::FnDef(def_id, substs) = *ty.kind() {
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
tcx.opt_associated_item(def_id)
{
debug!("find_self_call: args={:?}", args);
if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args {
if self_place.as_local() == Some(local) {
- return Some(def_id);
+ return Some((def_id, substs));
}
}
}
},
};
- overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()])
+ overloaded_place(
+ cx,
+ hir_expr,
+ adjustment.target,
+ Some(call),
+ vec![expr.to_ref()],
+ deref.span,
+ )
}
Adjust::Borrow(AutoBorrow::Ref(_, m)) => {
ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() }
hir::ExprKind::Index(ref lhs, ref index) => {
if cx.typeck_results().is_method_call(expr) {
- overloaded_place(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()])
+ overloaded_place(
+ cx,
+ expr,
+ expr_ty,
+ None,
+ vec![lhs.to_ref(), index.to_ref()],
+ expr.span,
+ )
} else {
ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref() }
}
hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => {
if cx.typeck_results().is_method_call(expr) {
- overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()])
+ overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()], expr.span)
} else {
ExprKind::Deref { arg: arg.to_ref() }
}
place_ty: Ty<'tcx>,
overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>,
args: Vec<ExprRef<'tcx>>,
+ span: Span,
) -> ExprKind<'tcx> {
// For an overloaded *x or x[y] expression of type T, the method
// call returns an &T and we must add the deref so that the types
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
let (region, mutbl) = match *recv_ty.kind() {
ty::Ref(region, _, mutbl) => (region, mutbl),
- _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"),
+ _ => span_bug!(span, "overloaded_place: receiver is not a reference"),
};
let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl });
// construct the complete expression `foo()` for the overloaded call,
// which will yield the &T type
let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id);
- let fun = method_callee(cx, expr, expr.span, overloaded_callee);
+ let fun = method_callee(cx, expr, span, overloaded_callee);
let ref_expr = Expr {
temp_lifetime,
ty: ref_ty,
- span: expr.span,
+ span,
kind: ExprKind::Call {
ty: fun.ty,
fun: fun.to_ref(),
args,
from_hir_call: false,
- fn_span: expr.span,
+ fn_span: span,
},
};
}
}
+ /// When writing a turbofish with multiple type parameters missing the leading `::`, we will
+ /// encounter a parse error when encountering the first `,`.
+ pub(super) fn check_mistyped_turbofish_with_multiple_type_params(
+ &mut self,
+ mut e: DiagnosticBuilder<'a>,
+ expr: &mut P<Expr>,
+ ) -> PResult<'a, ()> {
+ if let ExprKind::Binary(binop, _, _) = &expr.kind {
+ if let ast::BinOpKind::Lt = binop.node {
+ if self.eat(&token::Comma) {
+ let x = self.parse_seq_to_before_end(
+ &token::Gt,
+ SeqSep::trailing_allowed(token::Comma),
+ |p| p.parse_ty(),
+ );
+ match x {
+ Ok((_, _, false)) => {
+ self.bump(); // `>`
+ match self.parse_expr() {
+ Ok(_) => {
+ e.span_suggestion_verbose(
+ binop.span.shrink_to_lo(),
+ "use `::<...>` instead of `<...>` to specify type arguments",
+ "::".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ e.emit();
+ *expr = self.mk_expr_err(expr.span.to(self.prev_token.span));
+ return Ok(());
+ }
+ Err(mut err) => {
+ err.cancel();
+ }
+ }
+ }
+ Err(mut err) => {
+ err.cancel();
+ }
+ _ => {}
+ }
+ }
+ }
+ }
+ Err(e)
+ }
+
/// Check to see if a pair of chained operators looks like an attempt at chained comparison,
/// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
/// parenthesising the leftmost comparison.
let mut eat_semi = true;
match stmt.kind {
// Expression without semicolon.
- StmtKind::Expr(ref expr)
+ StmtKind::Expr(ref mut expr)
if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) =>
{
// Just check for errors and recover; do not eat semicolon yet.
);
}
}
- e.emit();
- self.recover_stmt();
+ if let Err(mut e) =
+ self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
+ {
+ e.emit();
+ self.recover_stmt();
+ }
// Don't complain about type errors in body tail after parse error (#57383).
let sp = expr.span.to(self.prev_token.span);
- stmt.kind = StmtKind::Expr(self.mk_expr_err(sp));
+ *expr = self.mk_expr_err(sp);
}
}
- StmtKind::Local(..) => {
- self.expect_semi()?;
+ StmtKind::Local(ref mut local) => {
+ if let Err(e) = self.expect_semi() {
+ // We might be at the `,` in `let x = foo<bar, baz>;`. Try to recover.
+ match &mut local.init {
+ Some(ref mut expr) => {
+ self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?;
+ // We found `foo<bar, baz>`, have we fully recovered?
+ self.expect_semi()?;
+ }
+ None => return Err(e),
+ }
+ }
eat_semi = false;
}
StmtKind::Empty => eat_semi = false,
}
fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
- let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
+ let and_span = self.prev_token.span;
+ let mut opt_lifetime =
+ if self.check_lifetime() { Some(self.expect_lifetime()) } else { None };
let mutbl = self.parse_mutability();
+ if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() {
+ // A lifetime is invalid here: it would be part of a bare trait bound, which requires
+ // it to be followed by a plus, but we disallow plus in the pointee type.
+ // So we can handle this case as an error here, and suggest `'a mut`.
+ // If there *is* a plus next though, handling the error later provides better suggestions
+ // (like adding parentheses)
+ if !self.look_ahead(1, |t| t.is_like_plus()) {
+ let lifetime_span = self.token.span;
+ let span = and_span.to(lifetime_span);
+
+ let mut err = self.struct_span_err(span, "lifetime must precede `mut`");
+ if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) {
+ err.span_suggestion(
+ span,
+ "place the lifetime before `mut`",
+ format!("&{} mut", lifetime_src),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ err.emit();
+
+ opt_lifetime = Some(self.expect_lifetime());
+ }
+ }
let ty = self.parse_ty_no_plus()?;
Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl }))
}
if let Some(t) = t {
self.check_def_id(t);
}
- if let Some(i) = i {
+ if let Some((i, _)) = i {
self.check_def_id(i);
}
}
match outer_res {
Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
if let Some(impl_span) =
- maybe_impl_defid.and_then(|def_id| self.opt_span(def_id))
+ maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id))
{
err.span_label(
reduce_impl_span_to_impl_keyword(sm, impl_span),
);
err
}
- ResolutionError::ParamInNonTrivialAnonConst(name) => {
+ ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => {
let mut err = self.session.struct_span_err(
span,
"generic parameters must not be used inside of non trivial constant values",
name
),
);
- err.help(
- &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name)
- );
+
+ if is_type {
+ err.note("type parameters are currently not permitted in anonymous constants");
+ } else {
+ err.help(
+ &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants",
+ name
+ )
+ );
+ }
+
err
}
ResolutionError::SelfInTyParamDefault => {
ItemRibKind(HasGenericParams),
/// We're in a constant item. Can't refer to dynamic stuff.
+ ///
+ /// The `bool` indicates if this constant may reference generic parameters
+ /// and is used to only allow generic parameters to be used in trivial constant expressions.
ConstantItemRibKind(bool),
/// We passed through a module.
self.with_current_self_item(item, |this| {
this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
let item_def_id = this.r.local_def_id(item.id).to_def_id();
- this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| {
+ this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| {
visit::walk_item(this, item);
});
});
// Resolve the trait reference, if necessary.
this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
let item_def_id = this.r.local_def_id(item_id).to_def_id();
- this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| {
+ this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| {
if let Some(trait_ref) = opt_trait_reference.as_ref() {
// Resolve type arguments in the trait path.
visit::walk_trait_ref(this, trait_ref);
/// generic parameters must not be used inside of non trivial constant values.
///
/// This error is only emitted when using `min_const_generics`.
- ParamInNonTrivialAnonConst(Symbol),
+ ParamInNonTrivialAnonConst { name: Symbol, is_type: bool },
/// Error E0735: type parameters with a default cannot use `Self`
SelfInTyParamDefault,
/// Error E0767: use of unreachable label
&mut self,
rib_index: usize,
rib_ident: Ident,
- res: Res,
+ mut res: Res,
record_used: bool,
span: Span,
all_ribs: &[Rib<'a>],
ConstantItemRibKind(trivial) => {
// HACK(min_const_generics): We currently only allow `N` or `{ N }`.
if !trivial && self.session.features_untracked().min_const_generics {
- if record_used {
- self.report_error(
- span,
- ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
- );
+ // HACK(min_const_generics): If we encounter `Self` in an anonymous constant
+ // we can't easily tell if it's generic at this stage, so we instead remember
+ // this and then enforce the self type to be concrete later on.
+ if let Res::SelfTy(trait_def, Some((impl_def, _))) = res {
+ res = Res::SelfTy(trait_def, Some((impl_def, true)));
+ } else {
+ if record_used {
+ self.report_error(
+ span,
+ ResolutionError::ParamInNonTrivialAnonConst {
+ name: rib_ident.name,
+ is_type: true,
+ },
+ );
+ }
+ return Res::Err;
}
- return Res::Err;
}
if in_ty_param_default {
if record_used {
self.report_error(
span,
- ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
+ ResolutionError::ParamInNonTrivialAnonConst {
+ name: rib_ident.name,
+ is_type: false,
+ },
);
}
return Res::Err;
///
/// The name is written with underscores, e.g., "unused_imports".
/// On the command line, underscores become dashes.
+ ///
+ /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming
+ /// for naming guidelines.
pub name: &'static str,
/// Default level for the lint.
+ ///
+ /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels
+ /// for guidelines on choosing a default level.
pub default_level: Level,
/// Description of the lint or the issue it detects.
}
/// Declares a static item of type `&'static Lint`.
+///
+/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html for documentation
+/// and guidelines on writing lints.
+///
+/// The macro call should start with a doc comment explaining the lint
+/// which will be embedded in the rustc user documentation book. It should
+/// be written in markdown and have a format that looks like this:
+///
+/// ```rust,ignore (doc-example)
+/// /// The `my_lint_name` lint detects [short explanation here].
+/// ///
+/// /// ### Example
+/// ///
+/// /// ```rust
+/// /// [insert a concise example that triggers the lint]
+/// /// ```
+/// ///
+/// /// {{produces}}
+/// ///
+/// /// ### Explanation
+/// ///
+/// /// This should be a detailed explanation of *why* the lint exists,
+/// /// and also include suggestions on how the user should fix the problem.
+/// /// Try to keep the text simple enough that a beginner can understand,
+/// /// and include links to other documentation for terminology that a
+/// /// beginner may not be familiar with. If this is "allow" by default,
+/// /// it should explain why (are there false positives or other issues?). If
+/// /// this is a future-incompatible lint, it should say so, with text that
+/// /// looks roughly like this:
+/// ///
+/// /// This is a [future-incompatible] lint to transition this to a hard
+/// /// error in the future. See [issue #xxxxx] for more details.
+/// ///
+/// /// [issue #xxxxx]: https://github.com/rust-lang/rust/issues/xxxxx
+/// ```
+///
+/// The `{{produces}}` tag will be automatically replaced with the output from
+/// the example by the build system. You can build and view the rustc book
+/// with `x.py doc --stage=1 src/doc/rustc --open`. If the lint example is too
+/// complex to run as a simple example (for example, it needs an extern
+/// crate), mark it with `ignore` and manually paste the expected output below
+/// the example.
#[macro_export]
macro_rules! declare_lint {
- ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
+ ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
$crate::declare_lint!(
- $vis $NAME, $Level, $desc,
+ $(#[$attr])* $vis $NAME, $Level, $desc,
);
);
- ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
+ ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
$(@future_incompatible = $fi:expr;)?
$(@feature_gate = $gate:expr;)?
$($v:ident),*) => (
+ $(#[$attr])*
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
name: stringify!($NAME),
default_level: $crate::lint::$Level,
..$crate::lint::Lint::default_fields_for_macro()
};
);
- ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
+ ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
$lint_edition: expr => $edition_level: ident
) => (
+ $(#[$attr])*
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
name: stringify!($NAME),
default_level: $crate::lint::$Level,
use rustc_span::symbol::sym;
declare_lint! {
+ /// The `ill_formed_attribute_input` lint detects ill-formed attribute
+ /// inputs that were previously accepted and used in practice.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #[inline = "this is not valid"]
+ /// fn foo() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Previously, inputs for many built-in attributes weren't validated and
+ /// nonsensical attribute inputs were accepted. After validation was
+ /// added, it was determined that some existing projects made use of these
+ /// invalid forms. This is a [future-incompatible] lint to transition this
+ /// to a hard error in the future. See [issue #57571] for more details.
+ ///
+ /// Check the [attribute reference] for details on the valid inputs for
+ /// attributes.
+ ///
+ /// [issue #57571]: https://github.com/rust-lang/rust/issues/57571
+ /// [attribute reference]: https://doc.rust-lang.org/nightly/reference/attributes.html
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub ILL_FORMED_ATTRIBUTE_INPUT,
Deny,
"ill-formed attribute inputs that were previously accepted and used in practice",
}
declare_lint! {
+ /// The `conflicting_repr_hints` lint detects [`repr` attributes] with
+ /// conflicting hints.
+ ///
+ /// [`repr` attributes]: https://doc.rust-lang.org/reference/type-layout.html#representations
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #[repr(u32, u64)]
+ /// enum Foo {
+ /// Variant1,
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The compiler incorrectly accepted these conflicting representations in
+ /// the past. This is a [future-incompatible] lint to transition this to a
+ /// hard error in the future. See [issue #68585] for more details.
+ ///
+ /// To correct the issue, remove one of the conflicting hints.
+ ///
+ /// [issue #68585]: https://github.com/rust-lang/rust/issues/68585
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub CONFLICTING_REPR_HINTS,
Deny,
"conflicts between `#[repr(..)]` hints that were previously accepted and used in practice",
}
declare_lint! {
+ /// The `meta_variable_misuse` lint detects possible meta-variable misuse
+ /// in macro definitions.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(meta_variable_misuse)]
+ ///
+ /// macro_rules! foo {
+ /// () => {};
+ /// ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* };
+ /// }
+ ///
+ /// fn main() {
+ /// foo!();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// There are quite a few different ways a [`macro_rules`] macro can be
+ /// improperly defined. Many of these errors were previously only detected
+ /// when the macro was expanded or not at all. This lint is an attempt to
+ /// catch some of these problems when the macro is *defined*.
+ ///
+ /// This lint is "allow" by default because it may have false positives
+ /// and other issues. See [issue #61053] for more details.
+ ///
+ /// [`macro_rules`]: https://doc.rust-lang.org/reference/macros-by-example.html
+ /// [issue #61053]: https://github.com/rust-lang/rust/issues/61053
pub META_VARIABLE_MISUSE,
Allow,
"possible meta-variable misuse at macro definition"
}
declare_lint! {
+ /// The `incomplete_include` lint detects the use of the [`include!`]
+ /// macro with a file that contains more than one expression.
+ ///
+ /// [`include!`]: https://doc.rust-lang.org/std/macro.include.html
+ ///
+ /// ### Example
+ ///
+ /// ```rust,ignore (needs separate file)
+ /// fn main() {
+ /// include!("foo.txt");
+ /// }
+ /// ```
+ ///
+ /// where the file `foo.txt` contains:
+ ///
+ /// ```text
+ /// println!("hi!");
+ /// ```
+ ///
+ /// produces:
+ ///
+ /// ```text
+ /// error: include macro expected single expression in source
+ /// --> foo.txt:1:14
+ /// |
+ /// 1 | println!("1");
+ /// | ^
+ /// |
+ /// = note: `#[deny(incomplete_include)]` on by default
+ /// ```
+ ///
+ /// ### Explanation
+ ///
+ /// The [`include!`] macro is currently only intended to be used to
+ /// include a single [expression] or multiple [items]. Historically it
+ /// would ignore any contents after the first expression, but that can be
+ /// confusing. In the example above, the `println!` expression ends just
+ /// before the semicolon, making the semicolon "extra" information that is
+ /// ignored. Perhaps even more surprising, if the included file had
+ /// multiple print statements, the subsequent ones would be ignored!
+ ///
+ /// One workaround is to place the contents in braces to create a [block
+ /// expression]. Also consider alternatives, like using functions to
+ /// encapsulate the expressions, or use [proc-macros].
+ ///
+ /// This is a lint instead of a hard error because existing projects were
+ /// found to hit this error. To be cautious, it is a lint for now. The
+ /// future semantics of the `include!` macro are also uncertain, see
+ /// [issue #35560].
+ ///
+ /// [items]: https://doc.rust-lang.org/reference/items.html
+ /// [expression]: https://doc.rust-lang.org/reference/expressions.html
+ /// [block expression]: https://doc.rust-lang.org/reference/expressions/block-expr.html
+ /// [proc-macros]: https://doc.rust-lang.org/reference/procedural-macros.html
+ /// [issue #35560]: https://github.com/rust-lang/rust/issues/35560
pub INCOMPLETE_INCLUDE,
Deny,
"trailing content in included file"
}
declare_lint! {
+ /// The `arithmetic_overflow` lint detects that an arithmetic operation
+ /// will [overflow].
+ ///
+ /// [overflow]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// 1_i32 << 32;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// It is very likely a mistake to perform an arithmetic operation that
+ /// overflows its value. If the compiler is able to detect these kinds of
+ /// overflows at compile-time, it will trigger this lint. Consider
+ /// adjusting the expression to avoid overflow, or use a data type that
+ /// will not overflow.
pub ARITHMETIC_OVERFLOW,
Deny,
"arithmetic operation overflows"
}
declare_lint! {
+ /// The `unconditional_panic` lint detects an operation that will cause a
+ /// panic at runtime.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// # #![allow(unused)]
+ /// let x = 1 / 0;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// This lint detects code that is very likely incorrect. When possible,
+ /// the compiler will attempt to detect situations where code can be
+ /// evaluated at compile-time to generate more efficient code. While
+ /// evaluating such code, if it detects that the code will unconditionally
+ /// panic, this usually indicates that it is doing something incorrectly.
+ /// If this lint is allowed, then the code will not be evaluated at
+ /// compile-time, and instead continue to generate code to evaluate at
+ /// runtime, which may panic during runtime.
pub UNCONDITIONAL_PANIC,
Deny,
"operation will cause a panic at runtime"
}
declare_lint! {
+ /// The `const_err` lint detects an erroneous expression while doing
+ /// constant evaluation.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![allow(unconditional_panic)]
+ /// let x: &'static i32 = &(1 / 0);
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// This lint detects code that is very likely incorrect. If this lint is
+ /// allowed, then the code will not be evaluated at compile-time, and
+ /// instead continue to generate code to evaluate at runtime, which may
+ /// panic during runtime.
+ ///
+ /// Note that this lint may trigger in either inside or outside of a
+ /// [const context]. Outside of a [const context], the compiler can
+ /// sometimes evaluate an expression at compile-time in order to generate
+ /// more efficient code. As the compiler becomes better at doing this, it
+ /// needs to decide what to do when it encounters code that it knows for
+ /// certain will panic or is otherwise incorrect. Making this a hard error
+ /// would prevent existing code that exhibited this behavior from
+ /// compiling, breaking backwards-compatibility. However, this is almost
+ /// certainly incorrect code, so this is a deny-by-default lint. For more
+ /// details, see [RFC 1229] and [issue #28238].
+ ///
+ /// Note that there are several other more specific lints associated with
+ /// compile-time evaluation, such as [`arithmetic_overflow`],
+ /// [`unconditional_panic`].
+ ///
+ /// [const context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
+ /// [RFC 1229]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md
+ /// [issue #28238]: https://github.com/rust-lang/rust/issues/28238
+ /// [`arithmetic_overflow`]: deny-by-default.html#arithmetic-overflow
+ /// [`unconditional_panic`]: deny-by-default.html#unconditional-panic
pub CONST_ERR,
Deny,
"constant evaluation detected erroneous expression",
}
declare_lint! {
+ /// The `unused_imports` lint detects imports that are never used.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// use std::collections::HashMap;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Unused imports may signal a mistake or unfinished code, and clutter
+ /// the code, and should be removed. If you intended to re-export the item
+ /// to make it available outside of the module, add a visibility modifier
+ /// like `pub`.
pub UNUSED_IMPORTS,
Warn,
"imports that are never used"
}
declare_lint! {
+ /// The `unused_extern_crates` lint guards against `extern crate` items
+ /// that are never used.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(unused_extern_crates)]
+ /// extern crate proc_macro;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// `extern crate` items that are unused have no effect and should be
+ /// removed. Note that there are some cases where specifying an `extern
+ /// crate` is desired for the side effect of ensuring the given crate is
+ /// linked, even though it is not otherwise directly referenced. The lint
+ /// can be silenced by aliasing the crate to an underscore, such as
+ /// `extern crate foo as _`. Also note that it is no longer idiomatic to
+ /// use `extern crate` in the [2018 edition], as extern crates are now
+ /// automatically added in scope.
+ ///
+ /// This lint is "allow" by default because it can be noisy, and produce
+ /// false-positives. If a dependency is being removed from a project, it
+ /// is recommended to remove it from the build configuration (such as
+ /// `Cargo.toml`) to ensure stale build entries aren't left behind.
+ ///
+ /// [2018 edition]: https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html#no-more-extern-crate
pub UNUSED_EXTERN_CRATES,
Allow,
"extern crates that are never used"
}
declare_lint! {
+ /// The `unused_crate_dependencies` lint detects crate dependencies that
+ /// are never used.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,ignore (needs extern crate)
+ /// #![deny(unused_crate_dependencies)]
+ /// ```
+ ///
+ /// This will produce:
+ ///
+ /// ```text
+ /// error: external crate `regex` unused in `lint_example`: remove the dependency or add `use regex as _;`
+ /// |
+ /// note: the lint level is defined here
+ /// --> src/lib.rs:1:9
+ /// |
+ /// 1 | #![deny(unused_crate_dependencies)]
+ /// | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ /// ```
+ ///
+ /// ### Explanation
+ ///
+ /// After removing the code that uses a dependency, this usually also
+ /// requires removing the dependency from the build configuration.
+ /// However, sometimes that step can be missed, which leads to time wasted
+ /// building dependencies that are no longer used. This lint can be
+ /// enabled to detect dependencies that are never used (more specifically,
+ /// any dependency passed with the `--extern` command-line flag that is
+ /// never referenced via [`use`], [`extern crate`], or in any [path]).
+ ///
+ /// This lint is "allow" by default because it can provide false positives
+ /// depending on how the build system is configured. For example, when
+ /// using Cargo, a "package" consists of multiple crates (such as a
+ /// library and a binary), but the dependencies are defined for the
+ /// package as a whole. If there is a dependency that is only used in the
+ /// binary, but not the library, then the lint will be incorrectly issued
+ /// in the library.
+ ///
+ /// [path]: https://doc.rust-lang.org/reference/paths.html
+ /// [`use`]: https://doc.rust-lang.org/reference/items/use-declarations.html
+ /// [`extern crate`]: https://doc.rust-lang.org/reference/items/extern-crates.html
pub UNUSED_CRATE_DEPENDENCIES,
Allow,
"crate dependencies that are never used",
}
declare_lint! {
+ /// The `unused_qualifications` lint detects unnecessarily qualified
+ /// names.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(unused_qualifications)]
+ /// mod foo {
+ /// pub fn bar() {}
+ /// }
+ ///
+ /// fn main() {
+ /// use foo::bar;
+ /// foo::bar();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// If an item from another module is already brought into scope, then
+ /// there is no need to qualify it in this case. You can call `bar()`
+ /// directly, without the `foo::`.
+ ///
+ /// This lint is "allow" by default because it is somewhat pedantic, and
+ /// doesn't indicate an actual problem, but rather a stylistic choice, and
+ /// can be noisy when refactoring or moving around code.
pub UNUSED_QUALIFICATIONS,
Allow,
"detects unnecessarily qualified names"
}
declare_lint! {
+ /// The `unknown_lints` lint detects unrecognized lint attribute.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![allow(not_a_real_lint)]
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// It is usually a mistake to specify a lint that does not exist. Check
+ /// the spelling, and check the lint listing for the correct name. Also
+ /// consider if you are using an old version of the compiler, and the lint
+ /// is only available in a newer version.
pub UNKNOWN_LINTS,
Warn,
"unrecognized lint attribute"
}
declare_lint! {
+ /// The `unused_variables` lint detects variables which are not used in
+ /// any way.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x = 5;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Unused variables may signal a mistake or unfinished code. To silence
+ /// the warning for the individual variable, prefix it with an underscore
+ /// such as `_x`.
pub UNUSED_VARIABLES,
Warn,
"detect variables which are not used in any way"
}
declare_lint! {
+ /// The `unused_assignments` lint detects assignments that will never be read.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let mut x = 5;
+ /// x = 6;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Unused assignments may signal a mistake or unfinished code. If the
+ /// variable is never used after being assigned, then the assignment can
+ /// be removed. Variables with an underscore prefix such as `_x` will not
+ /// trigger this lint.
pub UNUSED_ASSIGNMENTS,
Warn,
"detect assignments that will never be read"
}
declare_lint! {
+ /// The `dead_code` lint detects unused, unexported items.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// fn foo() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Dead code may signal a mistake or unfinished code. To silence the
+ /// warning for individual items, prefix the name with an underscore such
+ /// as `_foo`. If it was intended to expose the item outside of the crate,
+ /// consider adding a visibility modifier like `pub`. Otherwise consider
+ /// removing the unused code.
pub DEAD_CODE,
Warn,
"detect unused, unexported items"
}
declare_lint! {
+ /// The `unused_attributes` lint detects attributes that were not used by
+ /// the compiler.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![macro_export]
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Unused [attributes] may indicate the attribute is placed in the wrong
+ /// position. Consider removing it, or placing it in the correct position.
+ /// Also consider if you intended to use an _inner attribute_ (with a `!`
+ /// such as `#![allow(unused)]`) which applies to the item the attribute
+ /// is within, or an _outer attribute_ (without a `!` such as
+ /// `#[allow(unsued)]`) which applies to the item *following* the
+ /// attribute.
+ ///
+ /// [attributes]: https://doc.rust-lang.org/reference/attributes.html
pub UNUSED_ATTRIBUTES,
Warn,
"detects attributes that were not used by the compiler"
}
declare_lint! {
+ /// The `unreachable_code` lint detects unreachable code paths.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,no_run
+ /// panic!("we never go past here!");
+ ///
+ /// let x = 5;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Unreachable code may signal a mistake or unfinished code. If the code
+ /// is no longer in use, consider removing it.
pub UNREACHABLE_CODE,
Warn,
"detects unreachable code paths",
}
declare_lint! {
+ /// The `unreachable_patterns` lint detects unreachable patterns.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x = 5;
+ /// match x {
+ /// y => (),
+ /// 5 => (),
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// This usually indicates a mistake in how the patterns are specified or
+ /// ordered. In this example, the `y` pattern will always match, so the
+ /// five is impossible to reach. Remember, match arms match in order, you
+ /// probably wanted to put the `5` case above the `y` case.
pub UNREACHABLE_PATTERNS,
Warn,
"detects unreachable patterns"
}
declare_lint! {
+ /// The `overlapping_patterns` lint detects `match` arms that have
+ /// [range patterns] that overlap.
+ ///
+ /// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x = 123u8;
+ /// match x {
+ /// 0..=100 => { println!("small"); }
+ /// 100..=255 => { println!("large"); }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// It is likely a mistake to have range patterns in a match expression
+ /// that overlap. Check that the beginning and end values are what you
+ /// expect, and keep in mind that with `..=` the left and right bounds are
+ /// inclusive.
pub OVERLAPPING_PATTERNS,
Warn,
"detects overlapping patterns"
}
declare_lint! {
+ /// The `bindings_with_variant_name` lint detects pattern bindings with
+ /// the same name as one of the matched variants.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// pub enum Enum {
+ /// Foo,
+ /// Bar,
+ /// }
+ ///
+ /// pub fn foo(x: Enum) {
+ /// match x {
+ /// Foo => {}
+ /// Bar => {}
+ /// }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// It is usually a mistake to specify an enum variant name as an
+ /// [identifier pattern]. In the example above, the `match` arms are
+ /// specifying a variable name to bind the value of `x` to. The second arm
+ /// is ignored because the first one matches *all* values. The likely
+ /// intent is that the arm was intended to match on the enum variant.
+ ///
+ /// Two possible solutions are:
+ ///
+ /// * Specify the enum variant using a [path pattern], such as
+ /// `Enum::Foo`.
+ /// * Bring the enum variants into local scope, such as adding `use
+ /// Enum::*;` to the beginning of the `foo` function in the example
+ /// above.
+ ///
+ /// [identifier pattern]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns
+ /// [path pattern]: https://doc.rust-lang.org/reference/patterns.html#path-patterns
pub BINDINGS_WITH_VARIANT_NAME,
Warn,
"detects pattern bindings with the same name as one of the matched variants"
}
declare_lint! {
+ /// The `unused_macros` lint detects macros that were not used.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// macro_rules! unused {
+ /// () => {};
+ /// }
+ ///
+ /// fn main() {
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Unused macros may signal a mistake or unfinished code. To silence the
+ /// warning for the individual macro, prefix the name with an underscore
+ /// such as `_my_macro`. If you intended to export the macro to make it
+ /// available outside of the crate, use the [`macro_export` attribute].
+ ///
+ /// [`macro_export` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope
pub UNUSED_MACROS,
Warn,
"detects macros that were not used"
}
declare_lint! {
+ /// The `warnings` lint allows you to change the level of other
+ /// lints which produce warnings.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![deny(warnings)]
+ /// fn foo() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The `warnings` lint is a bit special; by changing its level, you
+ /// change every other warning that would produce a warning to whatever
+ /// value you'd like. As such, you won't ever trigger this lint in your
+ /// code directly.
pub WARNINGS,
Warn,
"mass-change the level for lints which produce warnings"
}
declare_lint! {
+ /// The `unused_features` lint detects unused or unknown features found in
+ /// crate-level [`feature` attributes].
+ ///
+ /// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/
+ ///
+ /// Note: This lint is currently not functional, see [issue #44232] for
+ /// more details.
+ ///
+ /// [issue #44232]: https://github.com/rust-lang/rust/issues/44232
pub UNUSED_FEATURES,
Warn,
"unused features found in crate-level `#[feature]` directives"
}
declare_lint! {
+ /// The `stable_features` lint detects a [`feature` attribute] that
+ /// has since been made stable.
+ ///
+ /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![feature(test_accepted_feature)]
+ /// fn main() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// When a feature is stabilized, it is no longer necessary to include a
+ /// `#![feature]` attribute for it. To fix, simply remove the
+ /// `#![feature]` attribute.
pub STABLE_FEATURES,
Warn,
"stable features found in `#[feature]` directive"
}
declare_lint! {
+ /// The `unknown_crate_types` lint detects an unknown crate type found in
+ /// a [`crate_type` attribute].
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![crate_type="lol"]
+ /// fn main() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// An unknown value give to the `crate_type` attribute is almost
+ /// certainly a mistake.
+ ///
+ /// [`crate_type` attribute]: https://doc.rust-lang.org/reference/linkage.html
pub UNKNOWN_CRATE_TYPES,
Deny,
"unknown crate type found in `#[crate_type]` directive",
}
declare_lint! {
+ /// The `trivial_casts` lint detects trivial casts which could be replaced
+ /// with coercion, which may require [type ascription] or a temporary
+ /// variable.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(trivial_casts)]
+ /// let x: &u32 = &42;
+ /// let y = x as *const u32;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// A trivial cast is a cast `e as T` where `e` has type `U` and `U` is a
+ /// subtype of `T`. This type of cast is usually unnecessary, as it can be
+ /// usually be inferred.
+ ///
+ /// This lint is "allow" by default because there are situations, such as
+ /// with FFI interfaces or complex type aliases, where it triggers
+ /// incorrectly, or in situations where it will be more difficult to
+ /// clearly express the intent. It may be possible that this will become a
+ /// warning in the future, possibly with [type ascription] providing a
+ /// convenient way to work around the current issues. See [RFC 401] for
+ /// historical context.
+ ///
+ /// [type ascription]: https://github.com/rust-lang/rust/issues/23416
+ /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
pub TRIVIAL_CASTS,
Allow,
"detects trivial casts which could be removed"
}
declare_lint! {
+ /// The `trivial_numeric_casts` lint detects trivial numeric casts of types
+ /// which could be removed.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(trivial_numeric_casts)]
+ /// let x = 42_i32 as i32;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// A trivial numeric cast is a cast of a numeric type to the same numeric
+ /// type. This type of cast is usually unnecessary.
+ ///
+ /// This lint is "allow" by default because there are situations, such as
+ /// with FFI interfaces or complex type aliases, where it triggers
+ /// incorrectly, or in situations where it will be more difficult to
+ /// clearly express the intent. It may be possible that this will become a
+ /// warning in the future, possibly with [type ascription] providing a
+ /// convenient way to work around the current issues. See [RFC 401] for
+ /// historical context.
+ ///
+ /// [type ascription]: https://github.com/rust-lang/rust/issues/23416
+ /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
pub TRIVIAL_NUMERIC_CASTS,
Allow,
"detects trivial casts of numeric types which could be removed"
}
declare_lint! {
+ /// The `private_in_public` lint detects private items in public
+ /// interfaces not caught by the old implementation.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # #![allow(unused)]
+ /// struct SemiPriv;
+ ///
+ /// mod m1 {
+ /// struct Priv;
+ /// impl super::SemiPriv {
+ /// pub fn f(_: Priv) {}
+ /// }
+ /// }
+ /// # fn main() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The visibility rules are intended to prevent exposing private items in
+ /// public interfaces. This is a [future-incompatible] lint to transition
+ /// this to a hard error in the future. See [issue #34537] for more
+ /// details.
+ ///
+ /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub PRIVATE_IN_PUBLIC,
Warn,
"detect private items in public interfaces not caught by the old implementation",
}
declare_lint! {
+ /// The `exported_private_dependencies` lint detects private dependencies
+ /// that are exposed in a public interface.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,ignore (needs-dependency)
+ /// pub fn foo() -> Option<some_private_dependency::Thing> {
+ /// None
+ /// }
+ /// ```
+ ///
+ /// This will produce:
+ ///
+ /// ```text
+ /// warning: type `bar::Thing` from private dependency 'bar' in public interface
+ /// --> src/lib.rs:3:1
+ /// |
+ /// 3 | pub fn foo() -> Option<bar::Thing> {
+ /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ /// |
+ /// = note: `#[warn(exported_private_dependencies)]` on by default
+ /// ```
+ ///
+ /// ### Explanation
+ ///
+ /// Dependencies can be marked as "private" to indicate that they are not
+ /// exposed in the public interface of a crate. This can be used by Cargo
+ /// to independently resolve those dependencies because it can assume it
+ /// does not need to unify them with other packages using that same
+ /// dependency. This lint is an indication of a violation of that
+ /// contract.
+ ///
+ /// To fix this, avoid exposing the dependency in your public interface.
+ /// Or, switch the dependency to a public dependency.
+ ///
+ /// Note that support for this is only available on the nightly channel.
+ /// See [RFC 1977] for more details, as well as the [Cargo documentation].
+ ///
+ /// [RFC 1977]: https://github.com/rust-lang/rfcs/blob/master/text/1977-public-private-dependencies.md
+ /// [Cargo documentation]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#public-dependency
pub EXPORTED_PRIVATE_DEPENDENCIES,
Warn,
"public interface leaks type from a private dependency"
}
declare_lint! {
+ /// The `pub_use_of_private_extern_crate` lint detects a specific
+ /// situation of re-exporting a private `extern crate`.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// extern crate core;
+ /// pub use core as reexported_core;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// A public `use` declaration should not be used to publicly re-export a
+ /// private `extern crate`. `pub extern crate` should be used instead.
+ ///
+ /// This was historically allowed, but is not the intended behavior
+ /// according to the visibility rules. This is a [future-incompatible]
+ /// lint to transition this to a hard error in the future. See [issue
+ /// #34537] for more details.
+ ///
+ /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub PUB_USE_OF_PRIVATE_EXTERN_CRATE,
Deny,
"detect public re-exports of private extern crates",
}
declare_lint! {
+ /// The `invalid_type_param_default` lint detects type parameter defaults
+ /// erroneously allowed in an invalid location.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// fn foo<T=i32>(t: T) {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Default type parameters were only intended to be allowed in certain
+ /// situations, but historically the compiler allowed them everywhere.
+ /// This is a [future-incompatible] lint to transition this to a hard
+ /// error in the future. See [issue #36887] for more details.
+ ///
+ /// [issue #36887]: https://github.com/rust-lang/rust/issues/36887
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub INVALID_TYPE_PARAM_DEFAULT,
Deny,
"type parameter default erroneously allowed in invalid location",
}
declare_lint! {
+ /// The `renamed_and_removed_lints` lint detects lints that have been
+ /// renamed or removed.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![deny(raw_pointer_derive)]
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// To fix this, either remove the lint or use the new name. This can help
+ /// avoid confusion about lints that are no longer valid, and help
+ /// maintain consistency for renamed lints.
pub RENAMED_AND_REMOVED_LINTS,
Warn,
"lints that have been renamed or removed"
}
declare_lint! {
+ /// The `unaligned_references` lint detects unaligned references to fields
+ /// of [packed] structs.
+ ///
+ /// [packed]: https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(unaligned_references)]
+ ///
+ /// #[repr(packed)]
+ /// pub struct Foo {
+ /// field1: u64,
+ /// field2: u8,
+ /// }
+ ///
+ /// fn main() {
+ /// unsafe {
+ /// let foo = Foo { field1: 0, field2: 0 };
+ /// let _ = &foo.field1;
+ /// }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Creating a reference to an insufficiently aligned packed field is
+ /// [undefined behavior] and should be disallowed.
+ ///
+ /// This lint is "allow" by default because there is no stable
+ /// alternative, and it is not yet certain how widespread existing code
+ /// will trigger this lint.
+ ///
+ /// See [issue #27060] for more discussion.
+ ///
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ /// [issue #27060]: https://github.com/rust-lang/rust/issues/27060
pub UNALIGNED_REFERENCES,
Allow,
"detects unaligned references to fields of packed structs",
}
declare_lint! {
+ /// The `const_item_mutation` lint detects attempts to mutate a `const`
+ /// item.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// const FOO: [i32; 1] = [0];
+ ///
+ /// fn main() {
+ /// FOO[0] = 1;
+ /// // This will print "[0]".
+ /// println!("{:?}", FOO);
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Trying to directly mutate a `const` item is almost always a mistake.
+ /// What is happening in the example above is that a temporary copy of the
+ /// `const` is mutated, but the original `const` is not. Each time you
+ /// refer to the `const` by name (such as `FOO` in the example above), a
+ /// separate copy of the value is inlined at that location.
+ ///
+ /// This lint checks for writing directly to a field (`FOO.field =
+ /// some_value`) or array entry (`FOO[0] = val`), or taking a mutable
+ /// reference to the const item (`&mut FOO`), including through an
+ /// autoderef (`FOO.some_mut_self_method()`).
+ ///
+ /// There are various alternatives depending on what you are trying to
+ /// accomplish:
+ ///
+ /// * First, always reconsider using mutable globals, as they can be
+ /// difficult to use correctly, and can make the code more difficult to
+ /// use or understand.
+ /// * If you are trying to perform a one-time initialization of a global:
+ /// * If the value can be computed at compile-time, consider using
+ /// const-compatible values (see [Constant Evaluation]).
+ /// * For more complex single-initialization cases, consider using a
+ /// third-party crate, such as [`lazy_static`] or [`once_cell`].
+ /// * If you are using the [nightly channel], consider the new
+ /// [`lazy`] module in the standard library.
+ /// * If you truly need a mutable global, consider using a [`static`],
+ /// which has a variety of options:
+ /// * Simple data types can be directly defined and mutated with an
+ /// [`atomic`] type.
+ /// * More complex types can be placed in a synchronization primitive
+ /// like a [`Mutex`], which can be initialized with one of the options
+ /// listed above.
+ /// * A [mutable `static`] is a low-level primitive, requiring unsafe.
+ /// Typically This should be avoided in preference of something
+ /// higher-level like one of the above.
+ ///
+ /// [Constant Evaluation]: https://doc.rust-lang.org/reference/const_eval.html
+ /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
+ /// [mutable `static`]: https://doc.rust-lang.org/reference/items/static-items.html#mutable-statics
+ /// [`lazy`]: https://doc.rust-lang.org/nightly/std/lazy/index.html
+ /// [`lazy_static`]: https://crates.io/crates/lazy_static
+ /// [`once_cell`]: https://crates.io/crates/once_cell
+ /// [`atomic`]: https://doc.rust-lang.org/std/sync/atomic/index.html
+ /// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
pub CONST_ITEM_MUTATION,
Warn,
"detects attempts to mutate a `const` item",
}
declare_lint! {
+ /// The `safe_packed_borrows` lint detects borrowing a field in the
+ /// interior of a packed structure with alignment other than 1.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #[repr(packed)]
+ /// pub struct Unaligned<T>(pub T);
+ ///
+ /// pub struct Foo {
+ /// start: u8,
+ /// data: Unaligned<u32>,
+ /// }
+ ///
+ /// fn main() {
+ /// let x = Foo { start: 0, data: Unaligned(1) };
+ /// let y = &x.data.0;
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// This type of borrow is unsafe and can cause errors on some platforms
+ /// and violates some assumptions made by the compiler. This was
+ /// previously allowed unintentionally. This is a [future-incompatible]
+ /// lint to transition this to a hard error in the future. See [issue
+ /// #46043] for more details, including guidance on how to solve the
+ /// problem.
+ ///
+ /// [issue #46043]: https://github.com/rust-lang/rust/issues/46043
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub SAFE_PACKED_BORROWS,
Warn,
"safe borrows of fields of packed structs were erroneously allowed",
}
declare_lint! {
+ /// The `patterns_in_fns_without_body` lint detects `mut` identifier
+ /// patterns as a parameter in functions without a body.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// trait Trait {
+ /// fn foo(mut arg: u8);
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// To fix this, remove `mut` from the parameter in the trait definition;
+ /// it can be used in the implementation. That is, the following is OK:
+ ///
+ /// ```rust
+ /// trait Trait {
+ /// fn foo(arg: u8); // Removed `mut` here
+ /// }
+ ///
+ /// impl Trait for i32 {
+ /// fn foo(mut arg: u8) { // `mut` here is OK
+ ///
+ /// }
+ /// }
+ /// ```
+ ///
+ /// Trait definitions can define functions without a body to specify a
+ /// function that implementors must define. The parameter names in the
+ /// body-less functions are only allowed to be `_` or an [identifier] for
+ /// documentation purposes (only the type is relevant). Previous versions
+ /// of the compiler erroneously allowed [identifier patterns] with the
+ /// `mut` keyword, but this was not intended to be allowed. This is a
+ /// [future-incompatible] lint to transition this to a hard error in the
+ /// future. See [issue #35203] for more details.
+ ///
+ /// [identifier]: https://doc.rust-lang.org/reference/identifiers.html
+ /// [identifier patterns]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns
+ /// [issue #35203]: https://github.com/rust-lang/rust/issues/35203
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub PATTERNS_IN_FNS_WITHOUT_BODY,
Deny,
"patterns in functions without body were erroneously allowed",
}
declare_lint! {
+ /// The `late_bound_lifetime_arguments` lint detects generic lifetime
+ /// arguments in path segments with late bound lifetime parameters.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// struct S;
+ ///
+ /// impl S {
+ /// fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
+ /// }
+ ///
+ /// fn main() {
+ /// S.late::<'static>(&0, &0);
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// It is not clear how to provide arguments for early-bound lifetime
+ /// parameters if they are intermixed with late-bound parameters in the
+ /// same list. For now, providing any explicit arguments will trigger this
+ /// lint if late-bound parameters are present, so in the future a solution
+ /// can be adopted without hitting backward compatibility issues. This is
+ /// a [future-incompatible] lint to transition this to a hard error in the
+ /// future. See [issue #42868] for more details, along with a description
+ /// of the difference between early and late-bound parameters.
+ ///
+ /// [issue #42868]: https://github.com/rust-lang/rust/issues/42868
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub LATE_BOUND_LIFETIME_ARGUMENTS,
Warn,
"detects generic lifetime arguments in path segments with late bound lifetime parameters",
}
declare_lint! {
+ /// The `order_dependent_trait_objects` lint detects a trait coherency
+ /// violation that would allow creating two trait impls for the same
+ /// dynamic trait object involving marker traits.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// pub trait Trait {}
+ ///
+ /// impl Trait for dyn Send + Sync { }
+ /// impl Trait for dyn Sync + Send { }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// A previous bug caused the compiler to interpret traits with different
+ /// orders (such as `Send + Sync` and `Sync + Send`) as distinct types
+ /// when they were intended to be treated the same. This allowed code to
+ /// define separate trait implementations when there should be a coherence
+ /// error. This is a [future-incompatible] lint to transition this to a
+ /// hard error in the future. See [issue #56484] for more details.
+ ///
+ /// [issue #56484]: https://github.com/rust-lang/rust/issues/56484
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub ORDER_DEPENDENT_TRAIT_OBJECTS,
Deny,
"trait-object types were treated as different depending on marker-trait order",
}
declare_lint! {
+ /// The `coherence_leak_check` lint detects conflicting implementations of
+ /// a trait that are only distinguished by the old leak-check code.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// trait SomeTrait { }
+ /// impl SomeTrait for for<'a> fn(&'a u8) { }
+ /// impl<'a> SomeTrait for fn(&'a u8) { }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// In the past, the compiler would accept trait implementations for
+ /// identical functions that differed only in where the lifetime binder
+ /// appeared. Due to a change in the borrow checker implementation to fix
+ /// several bugs, this is no longer allowed. However, since this affects
+ /// existing code, this is a [future-incompatible] lint to transition this
+ /// to a hard error in the future.
+ ///
+ /// Code relying on this pattern should introduce "[newtypes]",
+ /// like `struct Foo(for<'a> fn(&'a u8))`.
+ ///
+ /// See [issue #56105] for more details.
+ ///
+ /// [issue #56105]: https://github.com/rust-lang/rust/issues/56105
+ /// [newtypes]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub COHERENCE_LEAK_CHECK,
Warn,
"distinct impls distinguished only by the leak-check code",
}
declare_lint! {
+ /// The `deprecated` lint detects use of deprecated items.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #[deprecated]
+ /// fn foo() {}
+ ///
+ /// fn bar() {
+ /// foo();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Items may be marked "deprecated" with the [`deprecated` attribute] to
+ /// indicate that they should no longer be used. Usually the attribute
+ /// should include a note on what to use instead, or check the
+ /// documentation.
+ ///
+ /// [`deprecated` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute
pub DEPRECATED,
Warn,
"detects use of deprecated items",
}
declare_lint! {
+ /// The `unused_unsafe` lint detects unnecessary use of an `unsafe` block.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// unsafe {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// If nothing within the block requires `unsafe`, then remove the
+ /// `unsafe` marker because it is not required and may cause confusion.
pub UNUSED_UNSAFE,
Warn,
"unnecessary use of an `unsafe` block"
}
declare_lint! {
+ /// The `unused_mut` lint detects mut variables which don't need to be
+ /// mutable.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let mut x = 5;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The preferred style is to only mark variables as `mut` if it is
+ /// required.
pub UNUSED_MUT,
Warn,
"detect mut variables which don't need to be mutable"
}
declare_lint! {
+ /// The `unconditional_recursion` lint detects functions that cannot
+ /// return without calling themselves.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// fn foo() {
+ /// foo();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// It is usually a mistake to have a recursive call that does not have
+ /// some condition to cause it to terminate. If you really intend to have
+ /// an infinite loop, using a `loop` expression is recommended.
pub UNCONDITIONAL_RECURSION,
Warn,
"functions that cannot return without calling themselves"
}
declare_lint! {
+ /// The `single_use_lifetimes` lint detects lifetimes that are only used
+ /// once.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(single_use_lifetimes)]
+ ///
+ /// fn foo<'a>(x: &'a u32) {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Specifying an explicit lifetime like `'a` in a function or `impl`
+ /// should only be used to link together two things. Otherwise, you should
+ /// just use `'_` to indicate that the lifetime is not linked to anything,
+ /// or elide the lifetime altogether if possible.
+ ///
+ /// This lint is "allow" by default because it was introduced at a time
+ /// when `'_` and elided lifetimes were first being introduced, and this
+ /// lint would be too noisy. Also, there are some known false positives
+ /// that it produces. See [RFC 2115] for historical context, and [issue
+ /// #44752] for more details.
+ ///
+ /// [RFC 2115]: https://github.com/rust-lang/rfcs/blob/master/text/2115-argument-lifetimes.md
+ /// [issue #44752]: https://github.com/rust-lang/rust/issues/44752
pub SINGLE_USE_LIFETIMES,
Allow,
"detects lifetime parameters that are only used once"
}
declare_lint! {
+ /// The `unused_lifetimes` lint detects lifetime parameters that are never
+ /// used.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #[deny(unused_lifetimes)]
+ ///
+ /// pub fn foo<'a>() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Unused lifetime parameters may signal a mistake or unfinished code.
+ /// Consider removing the parameter.
pub UNUSED_LIFETIMES,
Allow,
"detects lifetime parameters that are never used"
}
declare_lint! {
+ /// The `tyvar_behind_raw_pointer` lint detects raw pointer to an
+ /// inference variable.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,edition2015
+ /// // edition 2015
+ /// let data = std::ptr::null();
+ /// let _ = &data as *const *const ();
+ ///
+ /// if data.is_null() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// This kind of inference was previously allowed, but with the future
+ /// arrival of [arbitrary self types], this can introduce ambiguity. To
+ /// resolve this, use an explicit type instead of relying on type
+ /// inference.
+ ///
+ /// This is a [future-incompatible] lint to transition this to a hard
+ /// error in the 2018 edition. See [issue #46906] for more details. This
+ /// is currently a hard-error on the 2018 edition, and is "warn" by
+ /// default in the 2015 edition.
+ ///
+ /// [arbitrary self types]: https://github.com/rust-lang/rust/issues/44874
+ /// [issue #46906]: https://github.com/rust-lang/rust/issues/46906
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub TYVAR_BEHIND_RAW_POINTER,
Warn,
"raw pointer to an inference variable",
}
declare_lint! {
+ /// The `elided_lifetimes_in_paths` lint detects the use of hidden
+ /// lifetime parameters.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(elided_lifetimes_in_paths)]
+ /// struct Foo<'a> {
+ /// x: &'a u32
+ /// }
+ ///
+ /// fn foo(x: &Foo) {
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Elided lifetime parameters can make it difficult to see at a glance
+ /// that borrowing is occurring. This lint ensures that lifetime
+ /// parameters are always explicitly stated, even if it is the `'_`
+ /// [placeholder lifetime].
+ ///
+ /// This lint is "allow" by default because it has some known issues, and
+ /// may require a significant transition for old code.
+ ///
+ /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions
pub ELIDED_LIFETIMES_IN_PATHS,
Allow,
"hidden lifetime parameters in types are deprecated",
}
declare_lint! {
+ /// The `bare_trait_objects` lint suggests using `dyn Trait` for trait
+ /// objects.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// trait Trait { }
+ ///
+ /// fn takes_trait_object(_: Box<Trait>) {
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Without the `dyn` indicator, it can be ambiguous or confusing when
+ /// reading code as to whether or not you are looking at a trait object.
+ /// The `dyn` keyword makes it explicit, and adds a symmetry to contrast
+ /// with [`impl Trait`].
+ ///
+ /// [`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
pub BARE_TRAIT_OBJECTS,
Warn,
"suggest using `dyn Trait` for trait objects"
}
declare_lint! {
+ /// The `absolute_paths_not_starting_with_crate` lint detects fully
+ /// qualified paths that start with a module name instead of `crate`,
+ /// `self`, or an extern crate name
+ ///
+ /// ### Example
+ ///
+ /// ```rust,edition2015,compile_fail
+ /// #![deny(absolute_paths_not_starting_with_crate)]
+ ///
+ /// mod foo {
+ /// pub fn bar() {}
+ /// }
+ ///
+ /// fn main() {
+ /// ::foo::bar();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Rust [editions] allow the language to evolve without breaking
+ /// backwards compatibility. This lint catches code that uses absolute
+ /// paths in the style of the 2015 edition. In the 2015 edition, absolute
+ /// paths (those starting with `::`) refer to either the crate root or an
+ /// external crate. In the 2018 edition it was changed so that they only
+ /// refer to external crates. The path prefix `crate::` should be used
+ /// instead to reference items from the crate root.
+ ///
+ /// If you switch the compiler from the 2015 to 2018 edition without
+ /// updating the code, then it will fail to compile if the old style paths
+ /// are used. You can manually change the paths to use the `crate::`
+ /// prefix to transition to the 2018 edition.
+ ///
+ /// This lint solves the problem automatically. It is "allow" by default
+ /// because the code is perfectly valid in the 2015 edition. The [`cargo
+ /// fix`] tool with the `--edition` flag will switch this lint to "warn"
+ /// and automatically apply the suggested fix from the compiler. This
+ /// provides a completely automated way to update old code to the 2018
+ /// edition.
+ ///
+ /// [editions]: https://doc.rust-lang.org/edition-guide/
+ /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
Allow,
"fully qualified paths that start with a module name \
}
declare_lint! {
+ /// The `illegal_floating_point_literal_pattern` lint detects
+ /// floating-point literals used in patterns.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x = 42.0;
+ ///
+ /// match x {
+ /// 5.0 => {}
+ /// _ => {}
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Previous versions of the compiler accepted floating-point literals in
+ /// patterns, but it was later determined this was a mistake. The
+ /// semantics of comparing floating-point values may not be clear in a
+ /// pattern when contrasted with "structural equality". Typically you can
+ /// work around this by using a [match guard], such as:
+ ///
+ /// ```rust
+ /// # let x = 42.0;
+ ///
+ /// match x {
+ /// y if y == 5.0 => {}
+ /// _ => {}
+ /// }
+ /// ```
+ ///
+ /// This is a [future-incompatible] lint to transition this to a hard
+ /// error in the future. See [issue #41620] for more details.
+ ///
+ /// [issue #41620]: https://github.com/rust-lang/rust/issues/41620
+ /// [match guard]: https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
Warn,
"floating-point literals cannot be used in patterns",
}
declare_lint! {
+ /// The `unstable_name_collisions` lint detects that you have used a name
+ /// that the standard library plans to add in the future.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// trait MyIterator : Iterator {
+ /// // is_sorted is an unstable method that already exists on the Iterator trait
+ /// fn is_sorted(self) -> bool where Self: Sized {true}
+ /// }
+ ///
+ /// impl<T: ?Sized> MyIterator for T where T: Iterator { }
+ ///
+ /// let x = vec![1,2,3];
+ /// let _ = x.iter().is_sorted();
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// When new methods are added to traits in the standard library, they are
+ /// usually added in an "unstable" form which is only available on the
+ /// [nightly channel] with a [`feature` attribute]. If there is any
+ /// pre-existing code which extends a trait to have a method with the same
+ /// name, then the names will collide. In the future, when the method is
+ /// stabilized, this will cause an error due to the ambiguity. This lint
+ /// is an early-warning to let you know that there may be a collision in
+ /// the future. This can be avoided by adding type annotations to
+ /// disambiguate which trait method you intend to call, such as
+ /// `MyIterator::is_sorted(my_iter)` or renaming or removing the method.
+ ///
+ /// [nightly channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+ /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
pub UNSTABLE_NAME_COLLISIONS,
Warn,
"detects name collision with an existing but unstable method",
}
declare_lint! {
+ /// The `irrefutable_let_patterns` lint detects detects [irrefutable
+ /// patterns] in [if-let] and [while-let] statements.
+ ///
+ ///
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// if let _ = 123 {
+ /// println!("always runs!");
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// There usually isn't a reason to have an irrefutable pattern in an
+ /// if-let or while-let statement, because the pattern will always match
+ /// successfully. A [`let`] or [`loop`] statement will suffice. However,
+ /// when generating code with a macro, forbidding irrefutable patterns
+ /// would require awkward workarounds in situations where the macro
+ /// doesn't know if the pattern is refutable or not. This lint allows
+ /// macros to accept this form, while alerting for a possibly incorrect
+ /// use in normal code.
+ ///
+ /// See [RFC 2086] for more details.
+ ///
+ /// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability
+ /// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
+ /// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
+ /// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements
+ /// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops
+ /// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md
pub IRREFUTABLE_LET_PATTERNS,
Warn,
"detects irrefutable patterns in if-let and while-let statements"
}
declare_lint! {
+ /// The `unused_labels` lint detects [labels] that are never used.
+ ///
+ /// [labels]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#loop-labels
+ ///
+ /// ### Example
+ ///
+ /// ```rust,no_run
+ /// 'unused_label: loop {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Unused labels may signal a mistake or unfinished code. To silence the
+ /// warning for the individual label, prefix it with an underscore such as
+ /// `'_my_label:`.
pub UNUSED_LABELS,
Warn,
"detects labels that are never used"
}
declare_lint! {
+ /// The `broken_intra_doc_links` lint detects failures in resolving
+ /// intra-doc link targets. This is a `rustdoc` only lint, see the
+ /// documentation in the [rustdoc book].
+ ///
+ /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links
pub BROKEN_INTRA_DOC_LINKS,
Warn,
"failures in resolving intra-doc link targets"
}
declare_lint! {
+ /// The `invalid_codeblock_attributes` lint detects code block attributes
+ /// in documentation examples that have potentially mis-typed values. This
+ /// is a `rustdoc` only lint, see the documentation in the [rustdoc book].
+ ///
+ /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes
pub INVALID_CODEBLOCK_ATTRIBUTES,
Warn,
"codeblock attribute looks a lot like a known one"
}
declare_lint! {
+ /// The `missing_crate_level_docs` lint detects if documentation is
+ /// missing at the crate root. This is a `rustdoc` only lint, see the
+ /// documentation in the [rustdoc book].
+ ///
+ /// [rustdoc book]: ../../../rustdoc/lints.html#missing_crate_level_docs
pub MISSING_CRATE_LEVEL_DOCS,
Allow,
"detects crates with no crate-level documentation"
}
declare_lint! {
+ /// The `missing_doc_code_examples` lint detects publicly-exported items
+ /// without code samples in their documentation. This is a `rustdoc` only
+ /// lint, see the documentation in the [rustdoc book].
+ ///
+ /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples
pub MISSING_DOC_CODE_EXAMPLES,
Allow,
"detects publicly-exported items without code samples in their documentation"
}
declare_lint! {
+ /// The `private_doc_tests` lint detects code samples in docs of private
+ /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see
+ /// the documentation in the [rustdoc book].
+ ///
+ /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests
pub PRIVATE_DOC_TESTS,
Allow,
"detects code samples in docs of private items not documented by rustdoc"
}
declare_lint! {
+ /// The `where_clauses_object_safety` lint detects for [object safety] of
+ /// [where clauses].
+ ///
+ /// [object safety]: https://doc.rust-lang.org/reference/items/traits.html#object-safety
+ /// [where clauses]: https://doc.rust-lang.org/reference/items/generics.html#where-clauses
+ ///
+ /// ### Example
+ ///
+ /// ```rust,no_run
+ /// trait Trait {}
+ ///
+ /// trait X { fn foo(&self) where Self: Trait; }
+ ///
+ /// impl X for () { fn foo(&self) {} }
+ ///
+ /// impl Trait for dyn X {}
+ ///
+ /// // Segfault at opt-level 0, SIGILL otherwise.
+ /// pub fn main() { <dyn X as X>::foo(&()); }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The compiler previously allowed these object-unsafe bounds, which was
+ /// incorrect. This is a [future-incompatible] lint to transition this to
+ /// a hard error in the future. See [issue #51443] for more details.
+ ///
+ /// [issue #51443]: https://github.com/rust-lang/rust/issues/51443
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub WHERE_CLAUSES_OBJECT_SAFETY,
Warn,
"checks the object safety of where clauses",
}
declare_lint! {
+ /// The `proc_macro_derive_resolution_fallback` lint detects proc macro
+ /// derives using inaccessible names from parent modules.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,ignore (proc-macro)
+ /// // foo.rs
+ /// #![crate_type = "proc-macro"]
+ ///
+ /// extern crate proc_macro;
+ ///
+ /// use proc_macro::*;
+ ///
+ /// #[proc_macro_derive(Foo)]
+ /// pub fn foo1(a: TokenStream) -> TokenStream {
+ /// drop(a);
+ /// "mod __bar { static mut BAR: Option<Something> = None; }".parse().unwrap()
+ /// }
+ /// ```
+ ///
+ /// ```rust,ignore (needs-dependency)
+ /// // bar.rs
+ /// #[macro_use]
+ /// extern crate foo;
+ ///
+ /// struct Something;
+ ///
+ /// #[derive(Foo)]
+ /// struct Another;
+ ///
+ /// fn main() {}
+ /// ```
+ ///
+ /// This will produce:
+ ///
+ /// ```text
+ /// warning: cannot find type `Something` in this scope
+ /// --> src/main.rs:8:10
+ /// |
+ /// 8 | #[derive(Foo)]
+ /// | ^^^ names from parent modules are not accessible without an explicit import
+ /// |
+ /// = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+ /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ /// = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
+ /// ```
+ ///
+ /// ### Explanation
+ ///
+ /// If a proc-macro generates a module, the compiler unintentionally
+ /// allowed items in that module to refer to items in the crate root
+ /// without importing them. This is a [future-incompatible] lint to
+ /// transition this to a hard error in the future. See [issue #50504] for
+ /// more details.
+ ///
+ /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
Warn,
"detects proc macro derives using inaccessible names from parent modules",
}
declare_lint! {
+ /// The `macro_use_extern_crate` lint detects the use of the
+ /// [`macro_use` attribute].
+ ///
+ /// ### Example
+ ///
+ /// ```rust,ignore (needs extern crate)
+ /// #![deny(macro_use_extern_crate)]
+ ///
+ /// #[macro_use]
+ /// extern crate serde_json;
+ ///
+ /// fn main() {
+ /// let _ = json!{{}};
+ /// }
+ /// ```
+ ///
+ /// This will produce:
+ ///
+ /// ```text
+ /// error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead
+ /// --> src/main.rs:3:1
+ /// |
+ /// 3 | #[macro_use]
+ /// | ^^^^^^^^^^^^
+ /// |
+ /// note: the lint level is defined here
+ /// --> src/main.rs:1:9
+ /// |
+ /// 1 | #![deny(macro_use_extern_crate)]
+ /// | ^^^^^^^^^^^^^^^^^^^^^^
+ /// ```
+ ///
+ /// ### Explanation
+ ///
+ /// The [`macro_use` attribute] on an [`extern crate`] item causes
+ /// macros in that external crate to be brought into the prelude of the
+ /// crate, making the macros in scope everywhere. As part of the efforts
+ /// to simplify handling of dependencies in the [2018 edition], the use of
+ /// `extern crate` is being phased out. To bring macros from extern crates
+ /// into scope, it is recommended to use a [`use` import].
+ ///
+ /// This lint is "allow" by default because this is a stylistic choice
+ /// that has not been settled, see [issue #52043] for more information.
+ ///
+ /// [`macro_use` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute
+ /// [`use` import]: https://doc.rust-lang.org/reference/items/use-declarations.html
+ /// [issue #52043]: https://github.com/rust-lang/rust/issues/52043
pub MACRO_USE_EXTERN_CRATE,
Allow,
"the `#[macro_use]` attribute is now deprecated in favor of using macros \
}
declare_lint! {
+ /// The `macro_expanded_macro_exports_accessed_by_absolute_paths` lint
+ /// detects macro-expanded [`macro_export`] macros from the current crate
+ /// that cannot be referred to by absolute paths.
+ ///
+ /// [`macro_export`]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// macro_rules! define_exported {
+ /// () => {
+ /// #[macro_export]
+ /// macro_rules! exported {
+ /// () => {};
+ /// }
+ /// };
+ /// }
+ ///
+ /// define_exported!();
+ ///
+ /// fn main() {
+ /// crate::exported!();
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The intent is that all macros marked with the `#[macro_export]`
+ /// attribute are made available in the root of the crate. However, when a
+ /// `macro_rules!` definition is generated by another macro, the macro
+ /// expansion is unable to uphold this rule. This is a
+ /// [future-incompatible] lint to transition this to a hard error in the
+ /// future. See [issue #53495] for more details.
+ ///
+ /// [issue #53495]: https://github.com/rust-lang/rust/issues/53495
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
Deny,
"macro-expanded `macro_export` macros from the current crate \
}
declare_lint! {
+ /// The `explicit_outlives_requirements` lint detects unnecessary
+ /// lifetime bounds that can be inferred.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// # #![allow(unused)]
+ /// #![deny(explicit_outlives_requirements)]
+ ///
+ /// struct SharedRef<'a, T>
+ /// where
+ /// T: 'a,
+ /// {
+ /// data: &'a T,
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// If a `struct` contains a reference, such as `&'a T`, the compiler
+ /// requires that `T` outlives the lifetime `'a`. This historically
+ /// required writing an explicit lifetime bound to indicate this
+ /// requirement. However, this can be overly explicit, causing clutter and
+ /// unnecessary complexity. The language was changed to automatically
+ /// infer the bound if it is not specified. Specifically, if the struct
+ /// contains a reference, directly or indirectly, to `T` with lifetime
+ /// `'x`, then it will infer that `T: 'x` is a requirement.
+ ///
+ /// This lint is "allow" by default because it can be noisy for existing
+ /// code that already had these requirements. This is a stylistic choice,
+ /// as it is still valid to explicitly state the bound. It also has some
+ /// false positives that can cause confusion.
+ ///
+ /// See [RFC 2093] for more details.
+ ///
+ /// [RFC 2093]: https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md
pub EXPLICIT_OUTLIVES_REQUIREMENTS,
Allow,
"outlives requirements can be inferred"
}
declare_lint! {
+ /// The `indirect_structural_match` lint detects a `const` in a pattern
+ /// that manually implements [`PartialEq`] and [`Eq`].
+ ///
+ /// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html
+ /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(indirect_structural_match)]
+ ///
+ /// struct Plus(i32, i32);
+ /// const ONE_PLUS_TWO: &&Plus = &&Plus(1, 2);
+ ///
+ /// impl PartialEq for Plus {
+ /// fn eq(&self, other: &Self) -> bool {
+ /// self.0 + self.1 == other.0 + other.1
+ /// }
+ /// }
+ ///
+ /// impl Eq for Plus {}
+ ///
+ /// fn main() {
+ /// if let ONE_PLUS_TWO = &&Plus(3, 0) {
+ /// println!("semantic!");
+ /// } else {
+ /// println!("structural!");
+ /// }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The compiler unintentionally accepted this form in the past. This is a
+ /// [future-incompatible] lint to transition this to a hard error in the
+ /// future. See [issue #62411] for a complete description of the problem,
+ /// and some possible solutions.
+ ///
+ /// [issue #62411]: https://github.com/rust-lang/rust/issues/62411
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub INDIRECT_STRUCTURAL_MATCH,
// defaulting to allow until rust-lang/rust#62614 is fixed.
Allow,
}
declare_lint! {
+ /// The `deprecated_in_future` lint is internal to rustc and should not be
+ /// used by user code.
+ ///
+ /// This lint is only enabled in the standard library. It works with the
+ /// use of `#[rustc_deprecated]` with a `since` field of a version in the
+ /// future. This allows something to be marked as deprecated in a future
+ /// version, and then this lint will ensure that the item is no longer
+ /// used in the standard library. See the [stability documentation] for
+ /// more details.
+ ///
+ /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#rustc_deprecated
pub DEPRECATED_IN_FUTURE,
Allow,
"detects use of items that will be deprecated in a future version",
}
declare_lint! {
+ /// The `ambiguous_associated_items` lint detects ambiguity between
+ /// [associated items] and [enum variants].
+ ///
+ /// [associated items]: https://doc.rust-lang.org/reference/items/associated-items.html
+ /// [enum variants]: https://doc.rust-lang.org/reference/items/enumerations.html
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// enum E {
+ /// V
+ /// }
+ ///
+ /// trait Tr {
+ /// type V;
+ /// fn foo() -> Self::V;
+ /// }
+ ///
+ /// impl Tr for E {
+ /// type V = u8;
+ /// // `Self::V` is ambiguous because it may refer to the associated type or
+ /// // the enum variant.
+ /// fn foo() -> Self::V { 0 }
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Previous versions of Rust did not allow accessing enum variants
+ /// through [type aliases]. When this ability was added (see [RFC 2338]), this
+ /// introduced some situations where it can be ambiguous what a type
+ /// was referring to.
+ ///
+ /// To fix this ambiguity, you should use a [qualified path] to explicitly
+ /// state which type to use. For example, in the above example the
+ /// function can be written as `fn f() -> <Self as Tr>::V { 0 }` to
+ /// specifically refer to the associated type.
+ ///
+ /// This is a [future-incompatible] lint to transition this to a hard
+ /// error in the future. See [issue #57644] for more details.
+ ///
+ /// [issue #57644]: https://github.com/rust-lang/rust/issues/57644
+ /// [type aliases]: https://doc.rust-lang.org/reference/items/type-aliases.html#type-aliases
+ /// [RFC 2338]: https://github.com/rust-lang/rfcs/blob/master/text/2338-type-alias-enum-variants.md
+ /// [qualified path]: https://doc.rust-lang.org/reference/paths.html#qualified-paths
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub AMBIGUOUS_ASSOCIATED_ITEMS,
Deny,
"ambiguous associated items",
}
declare_lint! {
+ /// The `mutable_borrow_reservation_conflict` lint detects the reservation
+ /// of a two-phased borrow that conflicts with other shared borrows.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let mut v = vec![0, 1, 2];
+ /// let shared = &v;
+ /// v.push(shared.len());
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// This is a [future-incompatible] lint to transition this to a hard error
+ /// in the future. See [issue #59159] for a complete description of the
+ /// problem, and some possible solutions.
+ ///
+ /// [issue #59159]: https://github.com/rust-lang/rust/issues/59159
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub MUTABLE_BORROW_RESERVATION_CONFLICT,
Warn,
"reservation of a two-phased borrow conflicts with other shared borrows",
}
declare_lint! {
+ /// The `soft_unstable` lint detects unstable features that were
+ /// unintentionally allowed on stable.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #[cfg(test)]
+ /// extern crate test;
+ ///
+ /// #[bench]
+ /// fn name(b: &mut test::Bencher) {
+ /// b.iter(|| 123)
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The [`bench` attribute] was accidentally allowed to be specified on
+ /// the [stable release channel]. Turning this to a hard error would have
+ /// broken some projects. This lint allows those projects to continue to
+ /// build correctly when [`--cap-lints`] is used, but otherwise signal an
+ /// error that `#[bench]` should not be used on the stable channel. This
+ /// is a [future-incompatible] lint to transition this to a hard error in
+ /// the future. See [issue #64266] for more details.
+ ///
+ /// [issue #64266]: https://github.com/rust-lang/rust/issues/64266
+ /// [`bench` attribute]: https://doc.rust-lang.org/nightly/unstable-book/library-features/test.html
+ /// [stable release channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+ /// [`--cap-lints`]: https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
pub SOFT_UNSTABLE,
Deny,
"a feature gate that doesn't break dependent crates",
}
declare_lint! {
+ /// The `inline_no_sanitize` lint detects incompatible use of
+ /// [`#[inline(always)]`][inline] and [`#[no_sanitize(...)]`][no_sanitize].
+ ///
+ /// [inline]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute
+ /// [no_sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #![feature(no_sanitize)]
+ ///
+ /// #[inline(always)]
+ /// #[no_sanitize(address)]
+ /// fn x() {}
+ ///
+ /// fn main() {
+ /// x()
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// The use of the [`#[inline(always)]`][inline] attribute prevents the
+ /// the [`#[no_sanitize(...)]`][no_sanitize] attribute from working.
+ /// Consider temporarily removing `inline` attribute.
pub INLINE_NO_SANITIZE,
Warn,
"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`",
}
declare_lint! {
+ /// The `asm_sub_register` lint detects using only a subset of a register
+ /// for inline asm inputs.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,ignore (fails on system llvm)
+ /// #![feature(asm)]
+ ///
+ /// fn main() {
+ /// #[cfg(target_arch="x86_64")]
+ /// unsafe {
+ /// asm!("mov {0}, {0}", in(reg) 0i16);
+ /// }
+ /// }
+ /// ```
+ ///
+ /// This will produce:
+ ///
+ /// ```text
+ /// warning: formatting may not be suitable for sub-register argument
+ /// --> src/main.rs:6:19
+ /// |
+ /// 6 | asm!("mov {0}, {0}", in(reg) 0i16);
+ /// | ^^^ ^^^ ---- for this argument
+ /// |
+ /// = note: `#[warn(asm_sub_register)]` on by default
+ /// = help: use the `x` modifier to have the register formatted as `ax`
+ /// = help: or use the `r` modifier to keep the default formatting of `rax`
+ /// ```
+ ///
+ /// ### Explanation
+ ///
+ /// Registers on some architectures can use different names to refer to a
+ /// subset of the register. By default, the compiler will use the name for
+ /// the full register size. To explicitly use a subset of the register,
+ /// you can override the default by using a modifier on the template
+ /// string operand to specify when subregister to use. This lint is issued
+ /// if you pass in a value with a smaller data type than the default
+ /// register size, to alert you of possibly using the incorrect width. To
+ /// fix this, add the suggested modifier to the template, or cast the
+ /// value to the correct size.
+ ///
+ /// See [register template modifiers] for more details.
+ ///
+ /// [register template modifiers]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#register-template-modifiers
pub ASM_SUB_REGISTER,
Warn,
"using only a subset of a register for inline asm inputs",
}
declare_lint! {
+ /// The `unsafe_op_in_unsafe_fn` lint detects unsafe operations in unsafe
+ /// functions without an explicit unsafe block. This lint only works on
+ /// the [**nightly channel**] with the
+ /// `#![feature(unsafe_block_in_unsafe_fn)]` feature.
+ ///
+ /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![feature(unsafe_block_in_unsafe_fn)]
+ /// #![deny(unsafe_op_in_unsafe_fn)]
+ ///
+ /// unsafe fn foo() {}
+ ///
+ /// unsafe fn bar() {
+ /// foo();
+ /// }
+ ///
+ /// fn main() {}
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Currently, an [`unsafe fn`] allows any [unsafe] operation within its
+ /// body. However, this can increase the surface area of code that needs
+ /// to be scrutinized for proper behavior. The [`unsafe` block] provides a
+ /// convenient way to make it clear exactly which parts of the code are
+ /// performing unsafe operations. In the future, it is desired to change
+ /// it so that unsafe operations cannot be performed in an `unsafe fn`
+ /// without an `unsafe` block.
+ ///
+ /// The fix to this is to wrap the unsafe code in an `unsafe` block.
+ ///
+ /// This lint is "allow" by default because it has not yet been
+ /// stabilized, and is not yet complete. See [RFC #2585] and [issue
+ /// #71668] for more details
+ ///
+ /// [`unsafe fn`]: https://doc.rust-lang.org/reference/unsafe-functions.html
+ /// [`unsafe` block]: https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks
+ /// [unsafe]: https://doc.rust-lang.org/reference/unsafety.html
+ /// [RFC #2585]: https://github.com/rust-lang/rfcs/blob/master/text/2585-unsafe-block-in-unsafe-fn.md
+ /// [issue #71668]: https://github.com/rust-lang/rust/issues/71668
pub UNSAFE_OP_IN_UNSAFE_FN,
Allow,
"unsafe operations in unsafe functions without an explicit unsafe block are deprecated",
}
declare_lint! {
+ /// The `cenum_impl_drop_cast` lint detects an `as` cast of a field-less
+ /// `enum` that implements [`Drop`].
+ ///
+ /// [`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # #![allow(unused)]
+ /// enum E {
+ /// A,
+ /// }
+ ///
+ /// impl Drop for E {
+ /// fn drop(&mut self) {
+ /// println!("Drop");
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let e = E::A;
+ /// let i = e as u32;
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Casting a field-less `enum` that does not implement [`Copy`] to an
+ /// integer moves the value without calling `drop`. This can result in
+ /// surprising behavior if it was expected that `drop` should be called.
+ /// Calling `drop` automatically would be inconsistent with other move
+ /// operations. Since neither behavior is clear or consistent, it was
+ /// decided that a cast of this nature will no longer be allowed.
+ ///
+ /// This is a [future-incompatible] lint to transition this to a hard error
+ /// in the future. See [issue #73333] for more details.
+ ///
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
+ /// [issue #73333]: https://github.com/rust-lang/rust/issues/73333
+ /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
pub CENUM_IMPL_DROP_CAST,
Warn,
"a C-like enum implementing Drop is cast",
}
declare_lint! {
+ /// The `const_evaluatable_unchecked` lint detects a generic constant used
+ /// in a type.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// const fn foo<T>() -> usize {
+ /// if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T
+ /// 4
+ /// } else {
+ /// 8
+ /// }
+ /// }
+ ///
+ /// fn test<T>() {
+ /// let _ = [0; foo::<T>()];
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// In the 1.43 release, some uses of generic parameters in array repeat
+ /// expressions were accidentally allowed. This is a [future-incompatible]
+ /// lint to transition this to a hard error in the future. See [issue
+ /// #76200] for a more detailed description and possible fixes.
+ ///
+ /// [future-incompatible]: ../index.md#future-incompatible-lints
+ /// [issue #76200]: https://github.com/rust-lang/rust/issues/76200
pub CONST_EVALUATABLE_UNCHECKED,
Warn,
"detects a generic constant is used in a type without a emitting a warning",
}
declare_lint! {
+ /// The `unused_doc_comments` lint detects doc comments that aren't used
+ /// by `rustdoc`.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// /// docs for x
+ /// let x = 12;
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// `rustdoc` does not use doc comments in all positions, and so the doc
+ /// comment will be ignored. Try changing it to a normal comment with `//`
+ /// to avoid the warning.
pub UNUSED_DOC_COMMENTS,
Warn,
"detects doc comments that aren't used by rustdoc"
}
/// Returns a `Span` that would enclose both `self` and `end`.
+ ///
+ /// ```text
+ /// ____ ___
+ /// self lorem ipsum end
+ /// ^^^^^^^^^^^^^^^^^^^^
+ /// ```
pub fn to(self, end: Span) -> Span {
let span_data = self.data();
let end_data = end.data();
}
/// Returns a `Span` between the end of `self` to the beginning of `end`.
+ ///
+ /// ```text
+ /// ____ ___
+ /// self lorem ipsum end
+ /// ^^^^^^^^^^^^^
+ /// ```
pub fn between(self, end: Span) -> Span {
let span = self.data();
let end = end.data();
)
}
- /// Returns a `Span` between the beginning of `self` to the beginning of `end`.
+ /// Returns a `Span` from the beginning of `self` until the beginning of `end`.
+ ///
+ /// ```text
+ /// ____ ___
+ /// self lorem ipsum end
+ /// ^^^^^^^^^^^^^^^^^
+ /// ```
pub fn until(self, end: Span) -> Span {
let span = self.data();
let end = end.data();
deny,
deprecated,
deref,
+ deref_method,
deref_mut,
+ deref_target,
derive,
diagnostic,
direct,
("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf),
("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf),
+ ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu),
("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf),
("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf),
("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu),
--- /dev/null
+use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult};
+
+pub fn target() -> TargetResult {
+ Ok(Target {
+ llvm_target: "riscv32-unknown-linux-gnu".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "32".to_string(),
+ target_c_int_width: "32".to_string(),
+ target_env: "gnu".to_string(),
+ data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(),
+ arch: "riscv32".to_string(),
+ target_os: "linux".to_string(),
+ target_vendor: "unknown".to_string(),
+ linker_flavor: LinkerFlavor::Gcc,
+ options: TargetOptions {
+ unsupported_abis: super::riscv_base::unsupported_abis(),
+ code_model: Some(CodeModel::Medium),
+ cpu: "generic-rv32".to_string(),
+ features: "+m,+a,+f,+d,+c".to_string(),
+ llvm_abiname: "ilp32d".to_string(),
+ max_atomic_width: Some(32),
+ ..super::linux_base::opts()
+ },
+ })
+}
// Meta infos:
infcx: &'a InferCtxt<'a, 'tcx>,
span: Span,
+ overloaded_span: Span,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
span: Span,
base_ty: Ty<'tcx>,
+ overloaded_span: Span,
) -> Autoderef<'a, 'tcx> {
Autoderef {
infcx,
span,
+ overloaded_span,
body_id,
param_env,
state: AutoderefSnapshot {
self.span
}
+ pub fn overloaded_span(&self) -> Span {
+ self.overloaded_span
+ }
+
pub fn reached_recursion_limit(&self) -> bool {
self.state.reached_recursion_limit
}
// avoid inundating the user with unnecessary errors, but we now
// check upstream for type errors and don't add the obligations to
// begin with in those cases.
- if self
- .tcx
- .lang_items()
- .sized_trait()
- .map_or(false, |sized_id| sized_id == trait_ref.def_id())
- {
+ if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit();
return;
}
};
if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() {
- let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty);
+ let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span);
if let Some(steps) = autoderef.find_map(|(ty, steps)| {
// Re-add the `&`
let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
.map(|i| chalk_ir::AssocTypeId(i.def_id))
.collect();
- let well_known = if self
- .interner
- .tcx
- .lang_items()
- .sized_trait()
- .map(|t| def_id == t)
- .unwrap_or(false)
- {
+ let well_known = if self.interner.tcx.lang_items().sized_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Sized)
- } else if self.interner.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false)
- {
+ } else if self.interner.tcx.lang_items().copy_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Copy)
- } else if self.interner.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false)
- {
+ } else if self.interner.tcx.lang_items().clone_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Clone)
- } else if self.interner.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false)
- {
+ } else if self.interner.tcx.lang_items().drop_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Drop)
- } else if self.interner.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) {
+ } else if self.interner.tcx.lang_items().fn_trait() == Some(def_id) {
Some(chalk_solve::rust_ir::WellKnownTrait::Fn)
} else if self
.interner
// Find the type of the associated item, and the trait where the associated
// item is declared.
let bound = match (&qself_ty.kind(), qself_res) {
- (_, Res::SelfTy(Some(_), Some(impl_def_id))) => {
+ (_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => {
// `Self` in an impl of a trait -- we have a concrete self type and a
// trait reference.
let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
self.prohibit_generics(path.segments);
tcx.types.self_param
}
- Res::SelfTy(_, Some(def_id)) => {
+ Res::SelfTy(_, Some((def_id, forbid_generic))) => {
// `Self` in impl (we know the concrete type).
assert_eq!(opt_self_ty, None);
self.prohibit_generics(path.segments);
// Try to evaluate any array length constants.
- self.normalize_ty(span, tcx.at(span).type_of(def_id))
+ let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id));
+ if forbid_generic && normalized_ty.needs_subst() {
+ let mut err = tcx.sess.struct_span_err(
+ path.span,
+ "generic `Self` types are currently not permitted in anonymous constants",
+ );
+ if let Some(hir::Node::Item(&hir::Item {
+ kind: hir::ItemKind::Impl { self_ty, .. },
+ ..
+ })) = tcx.hir().get_if_local(def_id)
+ {
+ err.span_note(self_ty.span, "not a concrete type");
+ }
+ err.emit();
+ tcx.ty_error()
+ } else {
+ normalized_ty
+ }
}
Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
use crate::check::coercion::CoerceMany;
use crate::check::{Diverges, Expectation, FnCtxt, Needs};
-use rustc_hir as hir;
-use rustc_hir::ExprKind;
+use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::ty::Ty;
+use rustc_infer::traits::Obligation;
+use rustc_middle::ty::{self, ToPredicate, Ty};
use rustc_span::Span;
-use rustc_trait_selection::traits::ObligationCauseCode;
-use rustc_trait_selection::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
+use rustc_trait_selection::opaque_types::InferCtxtExt as _;
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_trait_selection::traits::{
+ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
+};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn check_match(
expr: &'tcx hir::Expr<'tcx>,
scrut: &'tcx hir::Expr<'tcx>,
arms: &'tcx [hir::Arm<'tcx>],
- expected: Expectation<'tcx>,
+ orig_expected: Expectation<'tcx>,
match_src: hir::MatchSource,
) -> Ty<'tcx> {
let tcx = self.tcx;
use hir::MatchSource::*;
let (source_if, if_no_else, force_scrutinee_bool) = match match_src {
IfDesugar { contains_else_clause } => (true, !contains_else_clause, true),
- IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false),
+ IfLetDesugar { contains_else_clause, .. } => (true, !contains_else_clause, false),
WhileDesugar => (false, false, true),
_ => (false, false, false),
};
// type in that case)
let mut all_arms_diverge = Diverges::WarnedAlways;
- let expected = expected.adjust_for_branches(self);
+ let expected = orig_expected.adjust_for_branches(self);
let mut coercion = {
let coerce_first = match expected {
self.check_expr_with_expectation(&arm.body, expected)
};
all_arms_diverge &= self.diverges.get();
+
+ // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait`
+ // we check if the different arms would work with boxed trait objects instead and
+ // provide a structured suggestion in that case.
+ let opt_suggest_box_span = match (
+ orig_expected,
+ self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty)),
+ ) {
+ (Expectation::ExpectHasType(expected), Some((id, ty)))
+ if self.in_tail_expr && self.can_coerce(arm_ty, expected) =>
+ {
+ let impl_trait_ret_ty = self.infcx.instantiate_opaque_types(
+ id,
+ self.body_id,
+ self.param_env,
+ &ty,
+ arm.body.span,
+ );
+ let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty();
+ for o in impl_trait_ret_ty.obligations {
+ match o.predicate.skip_binders_unchecked() {
+ ty::PredicateAtom::Trait(t, constness) => {
+ let pred = ty::PredicateAtom::Trait(
+ ty::TraitPredicate {
+ trait_ref: ty::TraitRef {
+ def_id: t.def_id(),
+ substs: self.infcx.tcx.mk_substs_trait(arm_ty, &[]),
+ },
+ },
+ constness,
+ );
+ let obl = Obligation::new(
+ o.cause.clone(),
+ self.param_env,
+ pred.to_predicate(self.infcx.tcx),
+ );
+ suggest_box &= self.infcx.predicate_must_hold_modulo_regions(&obl);
+ if !suggest_box {
+ // We've encountered some obligation that didn't hold, so the
+ // return expression can't just be boxed. We don't need to
+ // evaluate the rest of the obligations.
+ break;
+ }
+ }
+ _ => {}
+ }
+ }
+ // If all the obligations hold (or there are no obligations) the tail expression
+ // we can suggest to return a boxed trait object instead of an opaque type.
+ if suggest_box { self.ret_type_span.clone() } else { None }
+ }
+ _ => None,
+ };
+
if source_if {
let then_expr = &arms[0].body;
match (i, if_no_else) {
(_, true) => {} // Handled above to avoid duplicated type errors (#60254).
(_, _) => {
let then_ty = prior_arm_ty.unwrap();
- let cause = self.if_cause(expr.span, then_expr, &arm.body, then_ty, arm_ty);
+ let cause = self.if_cause(
+ expr.span,
+ then_expr,
+ &arm.body,
+ then_ty,
+ arm_ty,
+ opt_suggest_box_span,
+ );
coercion.coerce(self, &cause, &arm.body, arm_ty);
}
}
prior_arms: other_arms.clone(),
last_ty: prior_arm_ty.unwrap(),
scrut_hir_id: scrut.hir_id,
+ opt_suggest_box_span,
}),
),
};
else_expr: &'tcx hir::Expr<'tcx>,
then_ty: Ty<'tcx>,
else_ty: Ty<'tcx>,
+ opt_suggest_box_span: Option<Span>,
) -> ObligationCause<'tcx> {
let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) {
// The `if`/`else` isn't in one line in the output, include some context to make it
error_sp,
ObligationCauseCode::IfExpression(box IfExpressionCause {
then: then_sp,
+ else_sp: error_sp,
outer: outer_sp,
semicolon: remove_semicolon,
+ opt_suggest_box_span,
}),
)
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
- Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
+ Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span)
+ }
+
+ /// Like `autoderef`, but provides a custom `Span` to use for calls to
+ /// an overloaded `Deref` operator
+ pub fn autoderef_overloaded_span(
+ &'a self,
+ span: Span,
+ base_ty: Ty<'tcx>,
+ overloaded_span: Span,
+ ) -> Autoderef<'a, 'tcx> {
+ Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span)
}
pub fn try_overloaded_deref(
|InferOk { value: method, obligations: o }| {
obligations.extend(o);
if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
- Some(OverloadedDeref { region, mutbl })
+ Some(OverloadedDeref {
+ region,
+ mutbl,
+ span: autoderef.overloaded_span(),
+ })
} else {
None
}
use crate::astconv::AstConv;
use crate::check::FnCtxt;
-use rustc_errors::{struct_span_err, DiagnosticBuilder};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
use rustc_middle::ty::{self, Ty, TypeAndMut};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
-use rustc_span::{self, Span};
+use rustc_span::{self, BytePos, Span};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
}
}
if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) {
- self.add_impl_trait_explanation(&mut err, fcx, expected, *sp, fn_output);
+ self.add_impl_trait_explanation(&mut err, cause, fcx, expected, *sp, fn_output);
}
err
}
fn add_impl_trait_explanation<'a>(
&self,
err: &mut DiagnosticBuilder<'a>,
+ cause: &ObligationCause<'tcx>,
fcx: &FnCtxt<'a, 'tcx>,
expected: Ty<'tcx>,
sp: Span,
};
if has_impl {
if is_object_safe {
- err.help(&format!(
- "you can instead return a boxed trait object using `Box<dyn {}>`",
- &snippet[5..]
- ));
+ err.multipart_suggestion(
+ "you could change the return type to be a boxed trait object",
+ vec![
+ (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box<dyn".to_string()),
+ (return_sp.shrink_to_hi(), ">".to_string()),
+ ],
+ Applicability::MachineApplicable,
+ );
+ let sugg = vec![sp, cause.span]
+ .into_iter()
+ .flat_map(|sp| {
+ vec![
+ (sp.shrink_to_lo(), "Box::new(".to_string()),
+ (sp.shrink_to_hi(), ")".to_string()),
+ ]
+ .into_iter()
+ })
+ .collect::<Vec<_>>();
+ err.multipart_suggestion(
+ "if you change the return type to expect trait objects, box the returned \
+ expressions",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
} else {
err.help(&format!(
"if the trait `{}` were object safe, you could return a boxed trait object",
}
err.note(trait_obj_msg);
}
- err.help("alternatively, create a new `enum` with a variant for each returned type");
+ err.help("you could instead create a new `enum` with a variant for each returned type");
}
fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
) -> Ty<'tcx> {
// Commit the autoderefs by calling `autoderef` again, but this
// time writing the results into the various typeck results.
- let mut autoderef = self.autoderef(self.span, unadjusted_self_ty);
+ let mut autoderef =
+ self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
let (_, n) = match autoderef.nth(pick.autoderefs) {
Some(n) => n,
None => {
tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
let ParamEnvAnd { param_env, value: self_ty } = goal;
- let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty)
- .include_raw_pointers()
- .silence_errors();
+ let mut autoderef =
+ Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP)
+ .include_raw_pointers()
+ .silence_errors();
let mut reached_raw_pointer = false;
let mut steps: Vec<_> = autoderef
.by_ref()
/// any).
ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
+ ret_coercion_impl_trait: Option<Ty<'tcx>>,
+
+ ret_type_span: Option<Span>,
+
+ /// Used exclusively to reduce cost of advanced evaluation used for
+ /// more helpful diagnostics.
+ in_tail_expr: bool,
+
/// First span of a return site that we find. Used in error messages.
ret_coercion_span: RefCell<Option<Span>>,
let hir = tcx.hir();
let declared_ret_ty = fn_sig.output();
+
let revealed_ret_ty =
fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span());
debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty);
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty)));
+ fcx.ret_type_span = Some(decl.output.span());
+ if let ty::Opaque(..) = declared_ret_ty.kind() {
+ fcx.ret_coercion_impl_trait = Some(declared_ret_ty);
+ }
fn_sig = tcx.mk_fn_sig(
fn_sig.inputs().iter().cloned(),
revealed_ret_ty,
inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
+ fcx.in_tail_expr = true;
if let ty::Dynamic(..) = declared_ret_ty.kind() {
// FIXME: We need to verify that the return type is `Sized` after the return expression has
// been evaluated so that we have types available for all the nodes being returned, but that
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
fcx.check_return_expr(&body.value);
}
+ fcx.in_tail_expr = false;
// We insert the deferred_generator_interiors entry after visiting the body.
// This ensures that all nested generators appear before the entry of this generator.
param_env,
err_count_on_creation: inh.tcx.sess.err_count(),
ret_coercion: None,
+ ret_coercion_impl_trait: None,
+ ret_type_span: None,
+ in_tail_expr: false,
ret_coercion_span: RefCell::new(None),
resume_yield_tys: None,
ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
None
}
})
- .collect::<Vec<_>>();
+ .collect::<Vec<usize>>();
// Both checked and coerced types could have matched, thus we need to remove
// duplicates.
- referenced_in.sort();
+
+ // We sort primitive type usize here and can use unstable sort
+ referenced_in.sort_unstable();
referenced_in.dedup();
if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) {
if no_accessible_unmentioned_fields {
unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields));
} else {
- unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields));
+ unmentioned_err =
+ Some(self.error_unmentioned_fields(pat, &unmentioned_fields, &fields));
}
}
match (inexistent_fields_err, unmentioned_err) {
&self,
pat: &Pat<'_>,
unmentioned_fields: &[(&ty::FieldDef, Ident)],
+ fields: &'tcx [hir::FieldPat<'tcx>],
) -> DiagnosticBuilder<'tcx> {
let field_names = if unmentioned_fields.len() == 1 {
format!("field `{}`", unmentioned_fields[0].1)
field_names
);
err.span_label(pat.span, format!("missing {}", field_names));
- if self.tcx.sess.teach(&err.get_code().unwrap()) {
- err.note(
- "This error indicates that a pattern for a struct fails to specify a \
- sub-pattern for every one of the struct's fields. Ensure that each field \
- from the struct's definition is mentioned in the pattern, or use `..` to \
- ignore unwanted fields.",
- );
- }
+ let len = unmentioned_fields.len();
+ let (prefix, postfix, sp) = match fields {
+ [] => match &pat.kind {
+ PatKind::Struct(path, [], false) => {
+ (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi()))
+ }
+ _ => return err,
+ },
+ [.., field] => (
+ match pat.kind {
+ PatKind::Struct(_, [_, ..], _) => ", ",
+ _ => "",
+ },
+ "",
+ field.span.shrink_to_hi(),
+ ),
+ };
+ err.span_suggestion(
+ sp,
+ &format!(
+ "include the missing field{} in the pattern",
+ if len == 1 { "" } else { "s" },
+ ),
+ format!(
+ "{}{}{}",
+ prefix,
+ unmentioned_fields
+ .iter()
+ .map(|(_, name)| name.to_string())
+ .collect::<Vec<_>>()
+ .join(", "),
+ postfix,
+ ),
+ Applicability::MachineApplicable,
+ );
+ err.span_suggestion(
+ sp,
+ &format!(
+ "if you don't care about {} missing field{}, you can explicitely ignore {}",
+ if len == 1 { "this" } else { "these" },
+ if len == 1 { "" } else { "s" },
+ if len == 1 { "it" } else { "them" },
+ ),
+ format!("{}..{}", prefix, postfix),
+ Applicability::MachineApplicable,
+ );
err
}
) {
let method = self.register_infer_ok_obligations(ok);
if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
- *deref = OverloadedDeref { region, mutbl };
+ *deref = OverloadedDeref { region, mutbl, span: deref.span };
}
// If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514).
// This helps avoid accidental drops.
# General build configuration options
# =============================================================================
[build]
+# The default stage to use for the `doc` subcommand
+#doc-stage = 0
+
+# The default stage to use for the `build` subcommand
+#build-stage = 1
+
+# The default stage to use for the `test` subcommand
+#test-stage = 1
+
+# The default stage to use for the `dist` subcommand
+#dist-stage = 2
+
+# The default stage to use for the `install` subcommand
+#install-stage = 2
+
+# The default stage to use for the `bench` subcommand
+#bench-stage = 2
# Build triple for the original snapshot compiler. This must be a compiler that
# nightlies are already produced for. The current platform must be able to run
#incremental = false
# Build a multi-threaded rustc
+# FIXME(#75760): Some UI tests fail when this option is enabled.
#parallel-compiler = false
# The default linker that will be hard-coded into the generated compiler for
#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
impl<T> From<BinaryHeap<T>> for Vec<T> {
+ /// Converts a `BinaryHeap<T>` into a `Vec<T>`.
+ ///
+ /// This conversion requires no data movement or allocation, and has
+ /// constant time complexity.
fn from(heap: BinaryHeap<T>) -> Vec<T> {
heap.data
}
LeafNode {
// As a general policy, we leave fields uninitialized if they can be, as this should
// be both slightly faster and easier to track in Valgrind.
- keys: [MaybeUninit::UNINIT; CAPACITY],
- vals: [MaybeUninit::UNINIT; CAPACITY],
+ keys: MaybeUninit::uninit_array(),
+ vals: MaybeUninit::uninit_array(),
parent: ptr::null(),
parent_idx: MaybeUninit::uninit(),
len: 0,
/// `len` of 0), there must be one initialized and valid edge. This function does not set up
/// such an edge.
unsafe fn new() -> Self {
- InternalNode { data: unsafe { LeafNode::new() }, edges: [MaybeUninit::UNINIT; 2 * B] }
+ InternalNode { data: unsafe { LeafNode::new() }, edges: MaybeUninit::uninit_array() }
}
}
where
R: RangeBounds<usize>,
{
- // SAFETY: This buffer is only used to check the range. It might be partially
- // uninitialized, but `check_range` needs a contiguous slice.
- // https://github.com/rust-lang/rust/pull/75207#discussion_r471193682
- let buffer = unsafe { slice::from_raw_parts(self.ptr(), self.len()) };
- let Range { start, end } = buffer.check_range(range);
+ let Range { start, end } = slice::check_range(self.len(), range);
let tail = self.wrap_add(self.tail, start);
let head = self.wrap_add(self.tail, end);
(tail, head)
#![cfg_attr(test, feature(test))]
#![feature(allocator_api)]
#![feature(array_chunks)]
+#![feature(array_windows)]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(box_patterns)]
#![feature(fn_traits)]
#![feature(fundamental)]
#![feature(inplace_iteration)]
-#![feature(internal_uninit_const)]
#![feature(lang_items)]
#![feature(layout_for_ptr)]
#![feature(libc)]
#![feature(unsized_locals)]
#![feature(allocator_internals)]
#![feature(slice_partition_dedup)]
-#![feature(maybe_uninit_extra, maybe_uninit_slice)]
+#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)]
#![feature(alloc_layout_extra)]
#![feature(trusted_random_access)]
#![feature(try_trait)]
use crate::boxed::Box;
use crate::vec::Vec;
+#[unstable(feature = "slice_check_range", issue = "76393")]
+pub use core::slice::check_range;
#[unstable(feature = "array_chunks", issue = "74985")]
pub use core::slice::ArrayChunks;
#[unstable(feature = "array_chunks", issue = "74985")]
pub use core::slice::ArrayChunksMut;
+#[unstable(feature = "array_windows", issue = "75027")]
+pub use core::slice::ArrayWindows;
#[stable(feature = "slice_get_slice", since = "1.28.0")]
pub use core::slice::SliceIndex;
#[stable(feature = "from_ref", since = "1.28.0")]
use core::ops::Bound::{Excluded, Included, Unbounded};
use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
use core::ptr;
+use core::slice;
use core::str::{lossy, pattern::Pattern};
use crate::borrow::{Cow, ToOwned};
// of the vector version. The data is just plain bytes.
// Because the range removal happens in Drop, if the Drain iterator is leaked,
// the removal will not happen.
- let Range { start, end } = self.as_bytes().check_range(range);
+ let Range { start, end } = slice::check_range(self.len(), range);
assert!(self.is_char_boundary(start));
assert!(self.is_char_boundary(end));
///
/// // ... and that's all!
/// // you can also do it like this:
-/// let x : &[usize] = &v;
+/// let u: &[usize] = &v;
+/// // or like this:
+/// let u: &[_] = &v;
/// ```
///
/// In Rust, it's more common to pass slices as arguments rather than vectors
// the hole, and the vector length is restored to the new length.
//
let len = self.len();
- let Range { start, end } = self.check_range(range);
+ let Range { start, end } = slice::check_range(len, range);
unsafe {
// set self.vec length's to start, to be safe in case Drain is leaked
assert_failed(at, self.len());
}
+ if at == 0 {
+ // the new vector can take over the original buffer and avoid the copy
+ return mem::replace(self, Vec::with_capacity(self.capacity()));
+ }
+
let other_len = self.len - at;
let mut other = Vec::with_capacity(other_len);
/// A draining iterator for `Vec<T>`.
///
/// This `struct` is created by [`Vec::drain`].
+/// See its documentation for more.
#[stable(feature = "drain", since = "1.6.0")]
pub struct Drain<'a, T: 'a> {
/// Index of tail to preserve
#![feature(slice_ptr_get)]
#![feature(split_inclusive)]
#![feature(binary_heap_retain)]
+#![feature(deque_range)]
#![feature(inplace_iteration)]
#![feature(iter_map_while)]
foo::<&str>("x");
}
+
+#[test]
+fn test_str_multiline() {
+ let a: String = "this \
+is a test"
+ .to_string();
+ let b: String = "this \
+ is \
+ another \
+ test"
+ .to_string();
+ assert_eq!(a, "this is a test".to_string());
+ assert_eq!(b, "this is another test".to_string());
+}
+
+#[test]
+fn test_str_escapes() {
+ let x = "\\\\\
+ ";
+ assert_eq!(x, r"\\"); // extraneous whitespace stripped
+}
use std::borrow::Cow;
use std::collections::TryReserveError::*;
use std::mem::size_of;
+use std::ops::Bound::*;
pub trait IntoCow<'a, B: ?Sized>
where
#[test]
#[should_panic]
fn test_split_off_mid_char() {
- let mut orig = String::from("山");
- let _ = orig.split_off(1);
+ let mut shan = String::from("山");
+ let _broken_mountain = shan.split_off(1);
}
#[test]
fn test_split_off_ascii() {
let mut ab = String::from("ABCD");
+ let orig_capacity = ab.capacity();
let cd = ab.split_off(2);
assert_eq!(ab, "AB");
assert_eq!(cd, "CD");
+ assert_eq!(ab.capacity(), orig_capacity);
}
#[test]
fn test_split_off_unicode() {
let mut nihon = String::from("日本語");
+ let orig_capacity = nihon.capacity();
let go = nihon.split_off("日本".len());
assert_eq!(nihon, "日本");
assert_eq!(go, "語");
+ assert_eq!(nihon.capacity(), orig_capacity);
}
#[test]
assert_eq!(t, "");
}
+#[test]
+#[should_panic]
+fn test_drain_start_overflow() {
+ let mut s = String::from("abc");
+ s.drain((Excluded(usize::MAX), Included(0)));
+}
+
+#[test]
+#[should_panic]
+fn test_drain_end_overflow() {
+ let mut s = String::from("abc");
+ s.drain((Included(0), Included(usize::MAX)));
+}
+
#[test]
fn test_replace_range() {
let mut s = "Hello, world!".to_owned();
s.replace_range(5..=5, "789");
}
+#[test]
+#[should_panic]
+fn test_replace_range_start_overflow() {
+ let mut s = String::from("123");
+ s.replace_range((Excluded(usize::MAX), Included(0)), "");
+}
+
+#[test]
+#[should_panic]
+fn test_replace_range_end_overflow() {
+ let mut s = String::from("456");
+ s.replace_range((Included(0), Included(usize::MAX)), "");
+}
+
#[test]
fn test_replace_range_empty() {
let mut s = String::from("12345");
use std::fmt::Debug;
use std::iter::InPlaceIterable;
use std::mem::size_of;
+use std::ops::Bound::*;
use std::panic::{catch_unwind, AssertUnwindSafe};
use std::rc::Rc;
use std::vec::{Drain, IntoIter};
assert_eq!(v.len(), usize::MAX - 1);
}
+#[test]
+#[should_panic]
+fn test_drain_index_overflow() {
+ let mut v = Vec::<()>::with_capacity(usize::MAX);
+ unsafe {
+ v.set_len(usize::MAX);
+ }
+ v.drain(0..=usize::MAX);
+}
+
#[test]
#[should_panic]
fn test_drain_inclusive_out_of_bounds() {
v.drain(5..=5);
}
+#[test]
+#[should_panic]
+fn test_drain_start_overflow() {
+ let mut v = vec![1, 2, 3];
+ v.drain((Excluded(usize::MAX), Included(0)));
+}
+
+#[test]
+#[should_panic]
+fn test_drain_end_overflow() {
+ let mut v = vec![1, 2, 3];
+ v.drain((Included(0), Included(usize::MAX)));
+}
+
#[test]
fn test_drain_leak() {
static mut DROPS: i32 = 0;
#[test]
fn test_split_off() {
let mut vec = vec![1, 2, 3, 4, 5, 6];
+ let orig_capacity = vec.capacity();
let vec2 = vec.split_off(4);
assert_eq!(vec, [1, 2, 3, 4]);
assert_eq!(vec2, [5, 6]);
+ assert_eq!(vec.capacity(), orig_capacity);
+}
+
+#[test]
+fn test_split_off_take_all() {
+ let mut vec = vec![1, 2, 3, 4, 5, 6];
+ let orig_ptr = vec.as_ptr();
+ let orig_capacity = vec.capacity();
+ let vec2 = vec.split_off(0);
+ assert_eq!(vec, []);
+ assert_eq!(vec2, [1, 2, 3, 4, 5, 6]);
+ assert_eq!(vec.capacity(), orig_capacity);
+ assert_eq!(vec2.as_ptr(), orig_ptr);
}
#[test]
#[test]
fn test_from_iter_specialization_with_iterator_adapters() {
fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {};
- let src: Vec<usize> = vec![0usize; 65535];
+ let src: Vec<usize> = vec![0usize; 256];
let srcptr = src.as_ptr();
let iter = src
.into_iter()
// Test that, if we reserved enough space, adding and removing elements does not
// invalidate references into the vector (such as `v0`). This test also
// runs in Miri, which would detect such problems.
+ // Note that this test does *not* constitute a stable guarantee that all these functions do not
+ // reallocate! Only what is explicitly documented at
+ // <https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#guarantees> is stably guaranteed.
let mut v = Vec::with_capacity(128);
v.push(13);
use std::collections::{vec_deque::Drain, VecDeque};
use std::fmt::Debug;
use std::mem::size_of;
+use std::ops::Bound::*;
use std::panic::{catch_unwind, AssertUnwindSafe};
use crate::hash;
deq[3];
}
+#[test]
+#[should_panic]
+fn test_range_start_overflow() {
+ let deq = VecDeque::from(vec![1, 2, 3]);
+ deq.range((Included(0), Included(usize::MAX)));
+}
+
+#[test]
+#[should_panic]
+fn test_range_end_overflow() {
+ let deq = VecDeque::from(vec![1, 2, 3]);
+ deq.range((Excluded(usize::MAX), Included(0)));
+}
+
#[derive(Clone, PartialEq, Debug)]
enum Taggy {
One(i32),
/// ```
#[inline]
#[must_use]
+ #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn reverse(self) -> Ordering {
+ pub const fn reverse(self) -> Ordering {
match self {
Less => Greater,
Equal => Equal,
/// ```
#[inline]
#[must_use]
+ #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")]
#[stable(feature = "ordering_chaining", since = "1.17.0")]
- pub fn then(self, other: Ordering) -> Ordering {
+ pub const fn then(self, other: Ordering) -> Ordering {
match self {
Equal => other,
_ => self,
#[inline]
#[unstable(feature = "test", issue = "50297")]
#[allow(unreachable_code)] // this makes #[cfg] a bit easier below.
-pub fn black_box<T>(dummy: T) -> T {
+pub fn black_box<T>(mut dummy: T) -> T {
// We need to "use" the argument in some way LLVM can't introspect, and on
// targets that support it we can typically leverage inline assembly to do
// this. LLVM's interpretation of inline assembly is that it's, well, a black
#[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
// SAFETY: the inline assembly is a no-op.
unsafe {
- llvm_asm!("" : : "r"(&dummy));
+ // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures.
+ llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
}
dummy
/// An iterator that links two iterators together, in a chain.
///
-/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`chain`]: trait.Iterator.html#method.chain
-/// [`Iterator`]: trait.Iterator.html
+/// This `struct` is created by [`Iterator::chain`]. See its documentation
+/// for more.
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
/// An iterator that maps each element to an iterator, and yields the elements
/// of the produced iterators.
///
-/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`flat_map`]: trait.Iterator.html#method.flat_map
-/// [`Iterator`]: trait.Iterator.html
+/// This `struct` is created by [`Iterator::flat_map`]. See its documentation
+/// for more.
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct FlatMap<I, U: IntoIterator, F> {
/// An iterator that iterates two other iterators simultaneously.
///
-/// This `struct` is created by the [`zip`] method on [`Iterator`]. See its
-/// documentation for more.
-///
-/// [`zip`]: trait.Iterator.html#method.zip
-/// [`Iterator`]: trait.Iterator.html
+/// This `struct` is created by [`Iterator::zip`]. See its documentation
+/// for more.
#[derive(Clone)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#![feature(untagged_unions)]
#![feature(unwind_attributes)]
#![feature(variant_count)]
-#![feature(doc_alias)]
+#![cfg_attr(bootstrap, feature(doc_alias))]
#![feature(mmx_target_feature)]
#![feature(tbm_target_feature)]
#![feature(sse4a_target_feature)]
unsafe { MaybeUninit::<[MaybeUninit<T>; LEN]>::uninit().assume_init() }
}
- /// A promotable constant, equivalent to `uninit()`.
- #[unstable(
- feature = "internal_uninit_const",
- issue = "none",
- reason = "hack to work around promotability"
- )]
- pub const UNINIT: Self = Self::uninit();
-
/// Creates a new `MaybeUninit<T>` in an uninitialized state, with the memory being
/// filled with `0` bytes. It depends on `T` whether that already makes for
/// proper initialization. For example, `MaybeUninit<usize>::zeroed()` is initialized,
/// forever in an unreachable state. However, it does not guarantee that pointers
/// to this memory will remain valid.
///
-/// * If you want to leak memory, see [`Box::leak`][leak].
-/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw].
+/// * If you want to leak memory, see [`Box::leak`].
+/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`].
/// * If you want to dispose of a value properly, running its destructor, see
-/// [`mem::drop`][drop].
+/// [`mem::drop`].
///
/// # Safety
///
/// ownership to `s` — the final step of interacting with `v` to dispose of it without
/// running its destructor is entirely avoided.
///
-/// [drop]: fn.drop.html
-/// [uninit]: fn.uninitialized.html
-/// [clone]: ../clone/trait.Clone.html
-/// [swap]: fn.swap.html
-/// [box]: ../../std/boxed/struct.Box.html
-/// [leak]: ../../std/boxed/struct.Box.html#method.leak
-/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw
+/// [`Box`]: ../../std/boxed/struct.Box.html
+/// [`Box::leak`]: ../../std/boxed/struct.Box.html#method.leak
+/// [`Box::into_raw`]: ../../std/boxed/struct.Box.html#method.into_raw
+/// [`mem::drop`]: drop
/// [ub]: ../../reference/behavior-considered-undefined.html
-/// [`ManuallyDrop`]: struct.ManuallyDrop.html
#[inline]
#[rustc_const_stable(feature = "const_forget", since = "1.46.0")]
#[stable(feature = "rust1", since = "1.0.0")]
///
/// This function is just a shim intended to be removed when the `unsized_locals` feature gets
/// stabilized.
-///
-/// [`forget`]: fn.forget.html
#[inline]
#[unstable(feature = "forget_unsized", issue = "none")]
pub fn forget_unsized<T: ?Sized>(t: T) {
/// assert_eq!(2, mem::size_of::<ExampleUnion>());
/// ```
///
-/// [alignment]: ./fn.align_of.html
+/// [alignment]: align_of
#[inline(always)]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
/// [slice]: ../../std/primitive.slice.html
/// [trait object]: ../../book/ch17-02-trait-objects.html
/// [extern type]: ../../unstable-book/language-features/extern-types.html
-/// [`size_of_val`]: ../../core/mem/fn.size_of_val.html
///
/// # Examples
///
/// [slice]: ../../std/primitive.slice.html
/// [trait object]: ../../book/ch17-02-trait-objects.html
/// [extern type]: ../../unstable-book/language-features/extern-types.html
-/// [`align_of_val`]: ../../core/mem/fn.align_of_val.html
///
/// # Examples
///
/// `needs_drop` explicitly. Types like [`HashMap`], on the other hand, have to drop
/// values one at a time and should use this API.
///
-/// [`drop_in_place`]: ../ptr/fn.drop_in_place.html
+/// [`drop_in_place`]: crate::ptr::drop_in_place
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
///
/// # Examples
/// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed].
/// It is useful for FFI sometimes, but should generally be avoided.
///
-/// [zeroed]: union.MaybeUninit.html#method.zeroed
+/// [zeroed]: MaybeUninit::zeroed
/// [ub]: ../../reference/behavior-considered-undefined.html
-/// [inv]: union.MaybeUninit.html#initialization-invariant
+/// [inv]: MaybeUninit#initialization-invariant
///
/// # Examples
///
/// (Notice that the rules around uninitialized integers are not finalized yet, but
/// until they are, it is advisable to avoid them.)
///
-/// [`MaybeUninit<T>`]: union.MaybeUninit.html
-/// [uninit]: union.MaybeUninit.html#method.uninit
-/// [assume_init]: union.MaybeUninit.html#method.assume_init
-/// [inv]: union.MaybeUninit.html#initialization-invariant
+/// [`MaybeUninit<T>`]: MaybeUninit
+/// [uninit]: MaybeUninit::uninit
+/// [assume_init]: MaybeUninit::assume_init
+/// [inv]: MaybeUninit#initialization-invariant
#[inline(always)]
#[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
#[stable(feature = "rust1", since = "1.0.0")]
/// assert_eq!(42, x);
/// assert_eq!(5, y);
/// ```
-///
-/// [`replace`]: fn.replace.html
-/// [`take`]: fn.take.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn swap<T>(x: &mut T, y: &mut T) {
/// assert_eq!(buffer.get_and_reset(), vec![0, 1]);
/// assert_eq!(buffer.buf.len(), 0);
/// ```
-///
-/// [`Clone`]: ../../std/clone/trait.Clone.html
-/// [`replace`]: fn.replace.html
-/// [`swap`]: fn.swap.html
#[inline]
#[stable(feature = "mem_take", since = "1.40.0")]
pub fn take<T: Default>(dest: &mut T) -> T {
/// assert_eq!(buffer.replace_index(0, 2), 0);
/// assert_eq!(buffer.buf[0], 2);
/// ```
-///
-/// [`Clone`]: ../../std/clone/trait.Clone.html
-/// [`swap`]: fn.swap.html
-/// [`take`]: fn.take.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[must_use = "if you don't need the old value, you can just assign the new value directly"]
/// Because `_x` is moved into the function, it is automatically dropped before
/// the function returns.
///
-/// [drop]: ../ops/trait.Drop.html
+/// [drop]: Drop
///
/// # Examples
///
/// println!("x: {}, y: {}", x, y.0); // still available
/// ```
///
-/// [`RefCell`]: ../../std/cell/struct.RefCell.html
-/// [`Copy`]: ../../std/marker/trait.Copy.html
+/// [`RefCell`]: crate::cell::RefCell
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn drop<T>(_x: T) {}
/// `T`.
///
/// [ub]: ../../reference/behavior-considered-undefined.html
-/// [size_of]: fn.size_of.html
///
/// # Examples
///
/// Opaque type representing the discriminant of an enum.
///
/// See the [`discriminant`] function in this module for more information.
-///
-/// [`discriminant`]: fn.discriminant.html
#[stable(feature = "discriminant_value", since = "1.21.0")]
pub struct Discriminant<T>(<T as DiscriminantKind>::Discriminant);
fn set_cw(cw: u16) {
// SAFETY: the `fldcw` instruction has been audited to be able to work correctly with
// any `u16`
- unsafe { llvm_asm!("fldcw $0" :: "m" (cw) :: "volatile") }
+ unsafe {
+ asm!(
+ "fldcw ({})",
+ in(reg) &cw,
+ // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9.
+ options(att_syntax, nostack),
+ )
+ }
}
/// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`.
pub fn set_precision<T>() -> FPUControlWord {
- let cw = 0u16;
+ let mut cw = 0_u16;
// Compute the value for the Precision Control field that is appropriate for `T`.
let cw_precision = match size_of::<T>() {
// `FPUControlWord` structure is dropped
// SAFETY: the `fnstcw` instruction has been audited to be able to work correctly with
// any `u16`
- unsafe { llvm_asm!("fnstcw $0" : "=*m" (&cw) ::: "volatile") }
+ unsafe {
+ asm!(
+ "fnstcw ({})",
+ in(reg) &mut cw,
+ // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9.
+ options(att_syntax, nostack),
+ )
+ }
// Set the control word to the desired precision. This is achieved by masking away the old
// precision (bits 8 and 9, 0x300) and replacing it with the precision flag computed above.
pub trait Deref {
/// The resulting type after dereferencing.
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_diagnostic_item = "deref_target"]
type Target: ?Sized;
/// Dereferences the value.
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_diagnostic_item = "deref_method"]
fn deref(&self) -> &Self::Target;
}
--- /dev/null
+//! Operations on ASCII `[u8]`.
+
+use crate::mem;
+
+#[lang = "slice_u8"]
+#[cfg(not(test))]
+impl [u8] {
+ /// Checks if all bytes in this slice are within the ASCII range.
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn is_ascii(&self) -> bool {
+ is_ascii(self)
+ }
+
+ /// Checks that two slices are an ASCII case-insensitive match.
+ ///
+ /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
+ /// but without allocating and copying temporaries.
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
+ self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.eq_ignore_ascii_case(b))
+ }
+
+ /// Converts this slice to its ASCII upper case equivalent in-place.
+ ///
+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new uppercased value without modifying the existing one, use
+ /// [`to_ascii_uppercase`].
+ ///
+ /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn make_ascii_uppercase(&mut self) {
+ for byte in self {
+ byte.make_ascii_uppercase();
+ }
+ }
+
+ /// Converts this slice to its ASCII lower case equivalent in-place.
+ ///
+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
+ /// but non-ASCII letters are unchanged.
+ ///
+ /// To return a new lowercased value without modifying the existing one, use
+ /// [`to_ascii_lowercase`].
+ ///
+ /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
+ #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[inline]
+ pub fn make_ascii_lowercase(&mut self) {
+ for byte in self {
+ byte.make_ascii_lowercase();
+ }
+ }
+}
+
+/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed
+/// from `../str/mod.rs`, which does something similar for utf8 validation.
+#[inline]
+fn contains_nonascii(v: usize) -> bool {
+ const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize;
+ (NONASCII_MASK & v) != 0
+}
+
+/// Optimized ASCII test that will use usize-at-a-time operations instead of
+/// byte-at-a-time operations (when possible).
+///
+/// The algorithm we use here is pretty simple. If `s` is too short, we just
+/// check each byte and be done with it. Otherwise:
+///
+/// - Read the first word with an unaligned load.
+/// - Align the pointer, read subsequent words until end with aligned loads.
+/// - Read the last `usize` from `s` with an unaligned load.
+///
+/// If any of these loads produces something for which `contains_nonascii`
+/// (above) returns true, then we know the answer is false.
+#[inline]
+fn is_ascii(s: &[u8]) -> bool {
+ const USIZE_SIZE: usize = mem::size_of::<usize>();
+
+ let len = s.len();
+ let align_offset = s.as_ptr().align_offset(USIZE_SIZE);
+
+ // If we wouldn't gain anything from the word-at-a-time implementation, fall
+ // back to a scalar loop.
+ //
+ // We also do this for architectures where `size_of::<usize>()` isn't
+ // sufficient alignment for `usize`, because it's a weird edge case.
+ if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::<usize>() {
+ return s.iter().all(|b| b.is_ascii());
+ }
+
+ // We always read the first word unaligned, which means `align_offset` is
+ // 0, we'd read the same value again for the aligned read.
+ let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset };
+
+ let start = s.as_ptr();
+ // SAFETY: We verify `len < USIZE_SIZE` above.
+ let first_word = unsafe { (start as *const usize).read_unaligned() };
+
+ if contains_nonascii(first_word) {
+ return false;
+ }
+ // We checked this above, somewhat implicitly. Note that `offset_to_aligned`
+ // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked
+ // above.
+ debug_assert!(offset_to_aligned <= len);
+
+ // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the
+ // middle chunk of the slice.
+ let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize };
+
+ // `byte_pos` is the byte index of `word_ptr`, used for loop end checks.
+ let mut byte_pos = offset_to_aligned;
+
+ // Paranoia check about alignment, since we're about to do a bunch of
+ // unaligned loads. In practice this should be impossible barring a bug in
+ // `align_offset` though.
+ debug_assert_eq!((word_ptr as usize) % mem::align_of::<usize>(), 0);
+
+ // Read subsequent words until the last aligned word, excluding the last
+ // aligned word by itself to be done in tail check later, to ensure that
+ // tail is always one `usize` at most to extra branch `byte_pos == len`.
+ while byte_pos < len - USIZE_SIZE {
+ debug_assert!(
+ // Sanity check that the read is in bounds
+ (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) &&
+ // And that our assumptions about `byte_pos` hold.
+ (word_ptr as usize) - (start as usize) == byte_pos
+ );
+
+ // SAFETY: We know `word_ptr` is properly aligned (because of
+ // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end
+ let word = unsafe { word_ptr.read() };
+ if contains_nonascii(word) {
+ return false;
+ }
+
+ byte_pos += USIZE_SIZE;
+ // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that
+ // after this `add`, `word_ptr` will be at most one-past-the-end.
+ word_ptr = unsafe { word_ptr.add(1) };
+ }
+
+ // Sanity check to ensure there really is only one `usize` left. This should
+ // be guaranteed by our loop condition.
+ debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE);
+
+ // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start.
+ let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() };
+
+ !contains_nonascii(last_word)
+}
--- /dev/null
+//! Comparison traits for `[T]`.
+
+use crate::cmp;
+use crate::cmp::Ordering::{self, Greater, Less};
+use crate::mem;
+
+use super::from_raw_parts;
+use super::memchr;
+
+extern "C" {
+ /// Calls implementation provided memcmp.
+ ///
+ /// Interprets the data as u8.
+ ///
+ /// Returns 0 for equal, < 0 for less than and > 0 for greater
+ /// than.
+ // FIXME(#32610): Return type should be c_int
+ fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<A, B> PartialEq<[B]> for [A]
+where
+ A: PartialEq<B>,
+{
+ fn eq(&self, other: &[B]) -> bool {
+ SlicePartialEq::equal(self, other)
+ }
+
+ fn ne(&self, other: &[B]) -> bool {
+ SlicePartialEq::not_equal(self, other)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Eq> Eq for [T] {}
+
+/// Implements comparison of vectors lexicographically.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Ord> Ord for [T] {
+ fn cmp(&self, other: &[T]) -> Ordering {
+ SliceOrd::compare(self, other)
+ }
+}
+
+/// Implements comparison of vectors lexicographically.
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: PartialOrd> PartialOrd for [T] {
+ fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
+ SlicePartialOrd::partial_compare(self, other)
+ }
+}
+
+#[doc(hidden)]
+// intermediate trait for specialization of slice's PartialEq
+trait SlicePartialEq<B> {
+ fn equal(&self, other: &[B]) -> bool;
+
+ fn not_equal(&self, other: &[B]) -> bool {
+ !self.equal(other)
+ }
+}
+
+// Generic slice equality
+impl<A, B> SlicePartialEq<B> for [A]
+where
+ A: PartialEq<B>,
+{
+ default fn equal(&self, other: &[B]) -> bool {
+ if self.len() != other.len() {
+ return false;
+ }
+
+ self.iter().zip(other.iter()).all(|(x, y)| x == y)
+ }
+}
+
+// Use an equal-pointer optimization when types are `Eq`
+// We can't make `A` and `B` the same type because `min_specialization` won't
+// allow it.
+impl<A, B> SlicePartialEq<B> for [A]
+where
+ A: MarkerEq<B>,
+{
+ default fn equal(&self, other: &[B]) -> bool {
+ if self.len() != other.len() {
+ return false;
+ }
+
+ // While performance would suffer if `guaranteed_eq` just returned `false`
+ // for all arguments, correctness and return value of this function are not affected.
+ if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
+ return true;
+ }
+
+ self.iter().zip(other.iter()).all(|(x, y)| x == y)
+ }
+}
+
+// Use memcmp for bytewise equality when the types allow
+impl<A, B> SlicePartialEq<B> for [A]
+where
+ A: BytewiseEquality<B>,
+{
+ fn equal(&self, other: &[B]) -> bool {
+ if self.len() != other.len() {
+ return false;
+ }
+
+ // While performance would suffer if `guaranteed_eq` just returned `false`
+ // for all arguments, correctness and return value of this function are not affected.
+ if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
+ return true;
+ }
+ // SAFETY: `self` and `other` are references and are thus guaranteed to be valid.
+ // The two slices have been checked to have the same size above.
+ unsafe {
+ let size = mem::size_of_val(self);
+ memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
+ }
+ }
+}
+
+#[doc(hidden)]
+// intermediate trait for specialization of slice's PartialOrd
+trait SlicePartialOrd: Sized {
+ fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
+}
+
+impl<A: PartialOrd> SlicePartialOrd for A {
+ default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
+ let l = cmp::min(left.len(), right.len());
+
+ // Slice to the loop iteration range to enable bound check
+ // elimination in the compiler
+ let lhs = &left[..l];
+ let rhs = &right[..l];
+
+ for i in 0..l {
+ match lhs[i].partial_cmp(&rhs[i]) {
+ Some(Ordering::Equal) => (),
+ non_eq => return non_eq,
+ }
+ }
+
+ left.len().partial_cmp(&right.len())
+ }
+}
+
+// This is the impl that we would like to have. Unfortunately it's not sound.
+// See `partial_ord_slice.rs`.
+/*
+impl<A> SlicePartialOrd for A
+where
+ A: Ord,
+{
+ default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
+ Some(SliceOrd::compare(left, right))
+ }
+}
+*/
+
+impl<A: AlwaysApplicableOrd> SlicePartialOrd for A {
+ fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
+ Some(SliceOrd::compare(left, right))
+ }
+}
+
+#[rustc_specialization_trait]
+trait AlwaysApplicableOrd: SliceOrd + Ord {}
+
+macro_rules! always_applicable_ord {
+ ($([$($p:tt)*] $t:ty,)*) => {
+ $(impl<$($p)*> AlwaysApplicableOrd for $t {})*
+ }
+}
+
+always_applicable_ord! {
+ [] u8, [] u16, [] u32, [] u64, [] u128, [] usize,
+ [] i8, [] i16, [] i32, [] i64, [] i128, [] isize,
+ [] bool, [] char,
+ [T: ?Sized] *const T, [T: ?Sized] *mut T,
+ [T: AlwaysApplicableOrd] &T,
+ [T: AlwaysApplicableOrd] &mut T,
+ [T: AlwaysApplicableOrd] Option<T>,
+}
+
+#[doc(hidden)]
+// intermediate trait for specialization of slice's Ord
+trait SliceOrd: Sized {
+ fn compare(left: &[Self], right: &[Self]) -> Ordering;
+}
+
+impl<A: Ord> SliceOrd for A {
+ default fn compare(left: &[Self], right: &[Self]) -> Ordering {
+ let l = cmp::min(left.len(), right.len());
+
+ // Slice to the loop iteration range to enable bound check
+ // elimination in the compiler
+ let lhs = &left[..l];
+ let rhs = &right[..l];
+
+ for i in 0..l {
+ match lhs[i].cmp(&rhs[i]) {
+ Ordering::Equal => (),
+ non_eq => return non_eq,
+ }
+ }
+
+ left.len().cmp(&right.len())
+ }
+}
+
+// memcmp compares a sequence of unsigned bytes lexicographically.
+// this matches the order we want for [u8], but no others (not even [i8]).
+impl SliceOrd for u8 {
+ #[inline]
+ fn compare(left: &[Self], right: &[Self]) -> Ordering {
+ let order =
+ // SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
+ // We use the minimum of both lengths which guarantees that both regions are
+ // valid for reads in that interval.
+ unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) };
+ if order == 0 {
+ left.len().cmp(&right.len())
+ } else if order < 0 {
+ Less
+ } else {
+ Greater
+ }
+ }
+}
+
+// Hack to allow specializing on `Eq` even though `Eq` has a method.
+#[rustc_unsafe_specialization_marker]
+trait MarkerEq<T>: PartialEq<T> {}
+
+impl<T: Eq> MarkerEq<T> for T {}
+
+#[doc(hidden)]
+/// Trait implemented for types that can be compared for equality using
+/// their bytewise representation
+#[rustc_specialization_trait]
+trait BytewiseEquality<T>: MarkerEq<T> + Copy {}
+
+macro_rules! impl_marker_for {
+ ($traitname:ident, $($ty:ty)*) => {
+ $(
+ impl $traitname<$ty> for $ty { }
+ )*
+ }
+}
+
+impl_marker_for!(BytewiseEquality,
+ u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool);
+
+pub(super) trait SliceContains: Sized {
+ fn slice_contains(&self, x: &[Self]) -> bool;
+}
+
+impl<T> SliceContains for T
+where
+ T: PartialEq,
+{
+ default fn slice_contains(&self, x: &[Self]) -> bool {
+ x.iter().any(|y| *y == *self)
+ }
+}
+
+impl SliceContains for u8 {
+ fn slice_contains(&self, x: &[Self]) -> bool {
+ memchr::memchr(*self, x).is_some()
+ }
+}
+
+impl SliceContains for i8 {
+ fn slice_contains(&self, x: &[Self]) -> bool {
+ let byte = *self as u8;
+ // SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()`
+ // as `*const u8` is safe. The `x.as_ptr()` comes from a reference and is thus guaranteed
+ // to be valid for reads for the length of the slice `x.len()`, which cannot be larger
+ // than `isize::MAX`. The returned slice is never mutated.
+ let bytes: &[u8] = unsafe { from_raw_parts(x.as_ptr() as *const u8, x.len()) };
+ memchr::memchr(byte, bytes).is_some()
+ }
+}
--- /dev/null
+//! Indexing implementations for `[T]`.
+
+use crate::ops::{self, Bound, Range, RangeBounds};
+use crate::ptr;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, I> ops::Index<I> for [T]
+where
+ I: SliceIndex<[T]>,
+{
+ type Output = I::Output;
+
+ #[inline]
+ fn index(&self, index: I) -> &I::Output {
+ index.index(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, I> ops::IndexMut<I> for [T]
+where
+ I: SliceIndex<[T]>,
+{
+ #[inline]
+ fn index_mut(&mut self, index: I) -> &mut I::Output {
+ index.index_mut(self)
+ }
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
+ panic!("range start index {} out of range for slice of length {}", index, len);
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+pub(super) fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
+ panic!("range end index {} out of range for slice of length {}", index, len);
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+pub(super) fn slice_index_order_fail(index: usize, end: usize) -> ! {
+ panic!("slice index starts at {} but ends at {}", index, end);
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+pub(super) fn slice_start_index_overflow_fail() -> ! {
+ panic!("attempted to index slice from after maximum usize");
+}
+
+#[inline(never)]
+#[cold]
+#[track_caller]
+pub(super) fn slice_end_index_overflow_fail() -> ! {
+ panic!("attempted to index slice up to maximum usize");
+}
+
+/// Performs bounds-checking of the given range.
+/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`]
+/// for slices of the given length.
+///
+/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
+/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
+///
+/// # Panics
+///
+/// Panics if the range is out of bounds.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(slice_check_range)]
+/// use std::slice;
+///
+/// let v = [10, 40, 30];
+/// assert_eq!(1..2, slice::check_range(v.len(), 1..2));
+/// assert_eq!(0..2, slice::check_range(v.len(), ..2));
+/// assert_eq!(1..3, slice::check_range(v.len(), 1..));
+/// ```
+///
+/// Panics when [`Index::index`] would panic:
+///
+/// ```should_panic
+/// #![feature(slice_check_range)]
+///
+/// std::slice::check_range(3, 2..1);
+/// ```
+///
+/// ```should_panic
+/// #![feature(slice_check_range)]
+///
+/// std::slice::check_range(3, 1..4);
+/// ```
+///
+/// ```should_panic
+/// #![feature(slice_check_range)]
+///
+/// std::slice::check_range(3, 1..=usize::MAX);
+/// ```
+///
+/// [`Index::index`]: ops::Index::index
+#[track_caller]
+#[unstable(feature = "slice_check_range", issue = "76393")]
+pub fn check_range<R: RangeBounds<usize>>(len: usize, range: R) -> Range<usize> {
+ let start = match range.start_bound() {
+ Bound::Included(&start) => start,
+ Bound::Excluded(start) => {
+ start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
+ }
+ Bound::Unbounded => 0,
+ };
+
+ let end = match range.end_bound() {
+ Bound::Included(end) => {
+ end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
+ }
+ Bound::Excluded(&end) => end,
+ Bound::Unbounded => len,
+ };
+
+ if start > end {
+ slice_index_order_fail(start, end);
+ }
+ if end > len {
+ slice_end_index_len_fail(end, len);
+ }
+
+ Range { start, end }
+}
+
+mod private_slice_index {
+ use super::ops;
+ #[stable(feature = "slice_get_slice", since = "1.28.0")]
+ pub trait Sealed {}
+
+ #[stable(feature = "slice_get_slice", since = "1.28.0")]
+ impl Sealed for usize {}
+ #[stable(feature = "slice_get_slice", since = "1.28.0")]
+ impl Sealed for ops::Range<usize> {}
+ #[stable(feature = "slice_get_slice", since = "1.28.0")]
+ impl Sealed for ops::RangeTo<usize> {}
+ #[stable(feature = "slice_get_slice", since = "1.28.0")]
+ impl Sealed for ops::RangeFrom<usize> {}
+ #[stable(feature = "slice_get_slice", since = "1.28.0")]
+ impl Sealed for ops::RangeFull {}
+ #[stable(feature = "slice_get_slice", since = "1.28.0")]
+ impl Sealed for ops::RangeInclusive<usize> {}
+ #[stable(feature = "slice_get_slice", since = "1.28.0")]
+ impl Sealed for ops::RangeToInclusive<usize> {}
+}
+
+/// A helper trait used for indexing operations.
+///
+/// Implementations of this trait have to promise that if the argument
+/// to `get_(mut_)unchecked` is a safe reference, then so is the result.
+#[stable(feature = "slice_get_slice", since = "1.28.0")]
+#[rustc_on_unimplemented(
+ on(T = "str", label = "string indices are ranges of `usize`",),
+ on(
+ all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"),
+ note = "you can use `.chars().nth()` or `.bytes().nth()`\n\
+ for more information, see chapter 8 in The Book: \
+ <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
+ ),
+ message = "the type `{T}` cannot be indexed by `{Self}`",
+ label = "slice indices are of type `usize` or ranges of `usize`"
+)]
+pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
+ /// The output type returned by methods.
+ #[stable(feature = "slice_get_slice", since = "1.28.0")]
+ type Output: ?Sized;
+
+ /// Returns a shared reference to the output at this location, if in
+ /// bounds.
+ #[unstable(feature = "slice_index_methods", issue = "none")]
+ fn get(self, slice: &T) -> Option<&Self::Output>;
+
+ /// Returns a mutable reference to the output at this location, if in
+ /// bounds.
+ #[unstable(feature = "slice_index_methods", issue = "none")]
+ fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>;
+
+ /// Returns a shared reference to the output at this location, without
+ /// performing any bounds checking.
+ /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
+ /// is *[undefined behavior]* even if the resulting reference is not used.
+ ///
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ #[unstable(feature = "slice_index_methods", issue = "none")]
+ unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;
+
+ /// Returns a mutable reference to the output at this location, without
+ /// performing any bounds checking.
+ /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
+ /// is *[undefined behavior]* even if the resulting reference is not used.
+ ///
+ /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+ #[unstable(feature = "slice_index_methods", issue = "none")]
+ unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output;
+
+ /// Returns a shared reference to the output at this location, panicking
+ /// if out of bounds.
+ #[unstable(feature = "slice_index_methods", issue = "none")]
+ #[track_caller]
+ fn index(self, slice: &T) -> &Self::Output;
+
+ /// Returns a mutable reference to the output at this location, panicking
+ /// if out of bounds.
+ #[unstable(feature = "slice_index_methods", issue = "none")]
+ #[track_caller]
+ fn index_mut(self, slice: &mut T) -> &mut Self::Output;
+}
+
+#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
+unsafe impl<T> SliceIndex<[T]> for usize {
+ type Output = T;
+
+ #[inline]
+ fn get(self, slice: &[T]) -> Option<&T> {
+ // SAFETY: `self` is checked to be in bounds.
+ if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None }
+ }
+
+ #[inline]
+ fn get_mut(self, slice: &mut [T]) -> Option<&mut T> {
+ // SAFETY: `self` is checked to be in bounds.
+ if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
+ // SAFETY: the caller guarantees that `slice` is not dangling, so it
+ // cannot be longer than `isize::MAX`. They also guarantee that
+ // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
+ // so the call to `add` is safe.
+ unsafe { slice.as_ptr().add(self) }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
+ // SAFETY: see comments for `get_unchecked` above.
+ unsafe { slice.as_mut_ptr().add(self) }
+ }
+
+ #[inline]
+ fn index(self, slice: &[T]) -> &T {
+ // N.B., use intrinsic indexing
+ &(*slice)[self]
+ }
+
+ #[inline]
+ fn index_mut(self, slice: &mut [T]) -> &mut T {
+ // N.B., use intrinsic indexing
+ &mut (*slice)[self]
+ }
+}
+
+#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
+ type Output = [T];
+
+ #[inline]
+ fn get(self, slice: &[T]) -> Option<&[T]> {
+ if self.start > self.end || self.end > slice.len() {
+ None
+ } else {
+ // SAFETY: `self` is checked to be valid and in bounds above.
+ unsafe { Some(&*self.get_unchecked(slice)) }
+ }
+ }
+
+ #[inline]
+ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+ if self.start > self.end || self.end > slice.len() {
+ None
+ } else {
+ // SAFETY: `self` is checked to be valid and in bounds above.
+ unsafe { Some(&mut *self.get_unchecked_mut(slice)) }
+ }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+ // SAFETY: the caller guarantees that `slice` is not dangling, so it
+ // cannot be longer than `isize::MAX`. They also guarantee that
+ // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
+ // so the call to `add` is safe.
+ unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+ // SAFETY: see comments for `get_unchecked` above.
+ unsafe {
+ ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
+ }
+ }
+
+ #[inline]
+ fn index(self, slice: &[T]) -> &[T] {
+ if self.start > self.end {
+ slice_index_order_fail(self.start, self.end);
+ } else if self.end > slice.len() {
+ slice_end_index_len_fail(self.end, slice.len());
+ }
+ // SAFETY: `self` is checked to be valid and in bounds above.
+ unsafe { &*self.get_unchecked(slice) }
+ }
+
+ #[inline]
+ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+ if self.start > self.end {
+ slice_index_order_fail(self.start, self.end);
+ } else if self.end > slice.len() {
+ slice_end_index_len_fail(self.end, slice.len());
+ }
+ // SAFETY: `self` is checked to be valid and in bounds above.
+ unsafe { &mut *self.get_unchecked_mut(slice) }
+ }
+}
+
+#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
+ type Output = [T];
+
+ #[inline]
+ fn get(self, slice: &[T]) -> Option<&[T]> {
+ (0..self.end).get(slice)
+ }
+
+ #[inline]
+ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+ (0..self.end).get_mut(slice)
+ }
+
+ #[inline]
+ unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+ unsafe { (0..self.end).get_unchecked(slice) }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+ unsafe { (0..self.end).get_unchecked_mut(slice) }
+ }
+
+ #[inline]
+ fn index(self, slice: &[T]) -> &[T] {
+ (0..self.end).index(slice)
+ }
+
+ #[inline]
+ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+ (0..self.end).index_mut(slice)
+ }
+}
+
+#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
+ type Output = [T];
+
+ #[inline]
+ fn get(self, slice: &[T]) -> Option<&[T]> {
+ (self.start..slice.len()).get(slice)
+ }
+
+ #[inline]
+ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+ (self.start..slice.len()).get_mut(slice)
+ }
+
+ #[inline]
+ unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+ unsafe { (self.start..slice.len()).get_unchecked(slice) }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+ unsafe { (self.start..slice.len()).get_unchecked_mut(slice) }
+ }
+
+ #[inline]
+ fn index(self, slice: &[T]) -> &[T] {
+ if self.start > slice.len() {
+ slice_start_index_len_fail(self.start, slice.len());
+ }
+ // SAFETY: `self` is checked to be valid and in bounds above.
+ unsafe { &*self.get_unchecked(slice) }
+ }
+
+ #[inline]
+ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+ if self.start > slice.len() {
+ slice_start_index_len_fail(self.start, slice.len());
+ }
+ // SAFETY: `self` is checked to be valid and in bounds above.
+ unsafe { &mut *self.get_unchecked_mut(slice) }
+ }
+}
+
+#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
+ type Output = [T];
+
+ #[inline]
+ fn get(self, slice: &[T]) -> Option<&[T]> {
+ Some(slice)
+ }
+
+ #[inline]
+ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+ Some(slice)
+ }
+
+ #[inline]
+ unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+ slice
+ }
+
+ #[inline]
+ unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+ slice
+ }
+
+ #[inline]
+ fn index(self, slice: &[T]) -> &[T] {
+ slice
+ }
+
+ #[inline]
+ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+ slice
+ }
+}
+
+#[stable(feature = "inclusive_range", since = "1.26.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
+ type Output = [T];
+
+ #[inline]
+ fn get(self, slice: &[T]) -> Option<&[T]> {
+ if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) }
+ }
+
+ #[inline]
+ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+ if *self.end() == usize::MAX {
+ None
+ } else {
+ (*self.start()..self.end() + 1).get_mut(slice)
+ }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+ unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+ unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
+ }
+
+ #[inline]
+ fn index(self, slice: &[T]) -> &[T] {
+ if *self.end() == usize::MAX {
+ slice_end_index_overflow_fail();
+ }
+ (*self.start()..self.end() + 1).index(slice)
+ }
+
+ #[inline]
+ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+ if *self.end() == usize::MAX {
+ slice_end_index_overflow_fail();
+ }
+ (*self.start()..self.end() + 1).index_mut(slice)
+ }
+}
+
+#[stable(feature = "inclusive_range", since = "1.26.0")]
+unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
+ type Output = [T];
+
+ #[inline]
+ fn get(self, slice: &[T]) -> Option<&[T]> {
+ (0..=self.end).get(slice)
+ }
+
+ #[inline]
+ fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
+ (0..=self.end).get_mut(slice)
+ }
+
+ #[inline]
+ unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
+ unsafe { (0..=self.end).get_unchecked(slice) }
+ }
+
+ #[inline]
+ unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
+ // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
+ unsafe { (0..=self.end).get_unchecked_mut(slice) }
+ }
+
+ #[inline]
+ fn index(self, slice: &[T]) -> &[T] {
+ (0..=self.end).index(slice)
+ }
+
+ #[inline]
+ fn index_mut(self, slice: &mut [T]) -> &mut [T] {
+ (0..=self.end).index_mut(slice)
+ }
+}
--- /dev/null
+//! Definitions of a bunch of iterators for `[T]`.
+
+#[macro_use] // import iterator! and forward_iterator!
+mod macros;
+
+use crate::cmp;
+use crate::cmp::Ordering;
+use crate::fmt;
+use crate::intrinsics::{assume, exact_div, unchecked_sub};
+use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess};
+use crate::marker::{self, Send, Sized, Sync};
+use crate::mem;
+use crate::ptr::NonNull;
+
+use super::{from_raw_parts, from_raw_parts_mut};
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> IntoIterator for &'a [T] {
+ type Item = &'a T;
+ type IntoIter = Iter<'a, T>;
+
+ fn into_iter(self) -> Iter<'a, T> {
+ self.iter()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> IntoIterator for &'a mut [T] {
+ type Item = &'a mut T;
+ type IntoIter = IterMut<'a, T>;
+
+ fn into_iter(self) -> IterMut<'a, T> {
+ self.iter_mut()
+ }
+}
+
+// Macro helper functions
+#[inline(always)]
+fn size_from_ptr<T>(_: *const T) -> usize {
+ mem::size_of::<T>()
+}
+
+/// Immutable slice iterator
+///
+/// This struct is created by the [`iter`] method on [slices].
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// // First, we declare a type which has `iter` method to get the `Iter` struct (&[usize here]):
+/// let slice = &[1, 2, 3];
+///
+/// // Then, we iterate over it:
+/// for element in slice.iter() {
+/// println!("{}", element);
+/// }
+/// ```
+///
+/// [`iter`]: ../../std/primitive.slice.html#method.iter
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Iter<'a, T: 'a> {
+ pub(super) ptr: NonNull<T>,
+ pub(super) end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
+ // ptr == end is a quick test for the Iterator being empty, that works
+ // for both ZST and non-ZST.
+ pub(super) _marker: marker::PhantomData<&'a T>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("Iter").field(&self.as_slice()).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Sync> Sync for Iter<'_, T> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Sync> Send for Iter<'_, T> {}
+
+impl<'a, T> Iter<'a, T> {
+ /// Views the underlying data as a subslice of the original data.
+ ///
+ /// This has the same lifetime as the original slice, and so the
+ /// iterator can continue to be used while this exists.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// // First, we declare a type which has the `iter` method to get the `Iter`
+ /// // struct (&[usize here]):
+ /// let slice = &[1, 2, 3];
+ ///
+ /// // Then, we get the iterator:
+ /// let mut iter = slice.iter();
+ /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]":
+ /// println!("{:?}", iter.as_slice());
+ ///
+ /// // Next, we move to the second element of the slice:
+ /// iter.next();
+ /// // Now `as_slice` returns "[2, 3]":
+ /// println!("{:?}", iter.as_slice());
+ /// ```
+ #[stable(feature = "iter_to_slice", since = "1.4.0")]
+ pub fn as_slice(&self) -> &'a [T] {
+ self.make_slice()
+ }
+}
+
+iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
+ fn is_sorted_by<F>(self, mut compare: F) -> bool
+ where
+ Self: Sized,
+ F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>,
+ {
+ self.as_slice().windows(2).all(|w| {
+ compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false)
+ })
+ }
+}}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Clone for Iter<'_, T> {
+ fn clone(&self) -> Self {
+ Iter { ptr: self.ptr, end: self.end, _marker: self._marker }
+ }
+}
+
+#[stable(feature = "slice_iter_as_ref", since = "1.13.0")]
+impl<T> AsRef<[T]> for Iter<'_, T> {
+ fn as_ref(&self) -> &[T] {
+ self.as_slice()
+ }
+}
+
+/// Mutable slice iterator.
+///
+/// This struct is created by the [`iter_mut`] method on [slices].
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// // First, we declare a type which has `iter_mut` method to get the `IterMut`
+/// // struct (&[usize here]):
+/// let mut slice = &mut [1, 2, 3];
+///
+/// // Then, we iterate over it and increment each element value:
+/// for element in slice.iter_mut() {
+/// *element += 1;
+/// }
+///
+/// // We now have "[2, 3, 4]":
+/// println!("{:?}", slice);
+/// ```
+///
+/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct IterMut<'a, T: 'a> {
+ pub(super) ptr: NonNull<T>,
+ pub(super) end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
+ // ptr == end is a quick test for the Iterator being empty, that works
+ // for both ZST and non-ZST.
+ pub(super) _marker: marker::PhantomData<&'a mut T>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("IterMut").field(&self.make_slice()).finish()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Sync> Sync for IterMut<'_, T> {}
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Send> Send for IterMut<'_, T> {}
+
+impl<'a, T> IterMut<'a, T> {
+ /// Views the underlying data as a subslice of the original data.
+ ///
+ /// To avoid creating `&mut` references that alias, this is forced
+ /// to consume the iterator.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// // First, we declare a type which has `iter_mut` method to get the `IterMut`
+ /// // struct (&[usize here]):
+ /// let mut slice = &mut [1, 2, 3];
+ ///
+ /// {
+ /// // Then, we get the iterator:
+ /// let mut iter = slice.iter_mut();
+ /// // We move to next element:
+ /// iter.next();
+ /// // So if we print what `into_slice` method returns here, we have "[2, 3]":
+ /// println!("{:?}", iter.into_slice());
+ /// }
+ ///
+ /// // Now let's modify a value of the slice:
+ /// {
+ /// // First we get back the iterator:
+ /// let mut iter = slice.iter_mut();
+ /// // We change the value of the first element of the slice returned by the `next` method:
+ /// *iter.next().unwrap() += 1;
+ /// }
+ /// // Now slice is "[2, 2, 3]":
+ /// println!("{:?}", slice);
+ /// ```
+ #[stable(feature = "iter_to_slice", since = "1.4.0")]
+ pub fn into_slice(self) -> &'a mut [T] {
+ // SAFETY: the iterator was created from a mutable slice with pointer
+ // `self.ptr` and length `len!(self)`. This guarantees that all the prerequisites
+ // for `from_raw_parts_mut` are fulfilled.
+ unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) }
+ }
+
+ /// Views the underlying data as a subslice of the original data.
+ ///
+ /// To avoid creating `&mut [T]` references that alias, the returned slice
+ /// borrows its lifetime from the iterator the method is applied on.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// # #![feature(slice_iter_mut_as_slice)]
+ /// let mut slice: &mut [usize] = &mut [1, 2, 3];
+ ///
+ /// // First, we get the iterator:
+ /// let mut iter = slice.iter_mut();
+ /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]":
+ /// assert_eq!(iter.as_slice(), &[1, 2, 3]);
+ ///
+ /// // Next, we move to the second element of the slice:
+ /// iter.next();
+ /// // Now `as_slice` returns "[2, 3]":
+ /// assert_eq!(iter.as_slice(), &[2, 3]);
+ /// ```
+ #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")]
+ pub fn as_slice(&self) -> &[T] {
+ self.make_slice()
+ }
+}
+
+iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}}
+
+/// An internal abstraction over the splitting iterators, so that
+/// splitn, splitn_mut etc can be implemented once.
+#[doc(hidden)]
+pub(super) trait SplitIter: DoubleEndedIterator {
+ /// Marks the underlying iterator as complete, extracting the remaining
+ /// portion of the slice.
+ fn finish(&mut self) -> Option<Self::Item>;
+}
+
+/// An iterator over subslices separated by elements that match a predicate
+/// function.
+///
+/// This struct is created by the [`split`] method on [slices].
+///
+/// [`split`]: ../../std/primitive.slice.html#method.split
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Split<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ pub(super) v: &'a [T],
+ pub(super) pred: P,
+ pub(super) finished: bool,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for Split<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish()
+ }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, P> Clone for Split<'_, T, P>
+where
+ P: Clone + FnMut(&T) -> bool,
+{
+ fn clone(&self) -> Self {
+ Split { v: self.v, pred: self.pred.clone(), finished: self.finished }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, P> Iterator for Split<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ type Item = &'a [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a [T]> {
+ if self.finished {
+ return None;
+ }
+
+ match self.v.iter().position(|x| (self.pred)(x)) {
+ None => self.finish(),
+ Some(idx) => {
+ let ret = Some(&self.v[..idx]);
+ self.v = &self.v[idx + 1..];
+ ret
+ }
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a [T]> {
+ if self.finished {
+ return None;
+ }
+
+ match self.v.iter().rposition(|x| (self.pred)(x)) {
+ None => self.finish(),
+ Some(idx) => {
+ let ret = Some(&self.v[idx + 1..]);
+ self.v = &self.v[..idx];
+ ret
+ }
+ }
+ }
+}
+
+impl<'a, T, P> SplitIter for Split<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ #[inline]
+ fn finish(&mut self) -> Option<&'a [T]> {
+ if self.finished {
+ None
+ } else {
+ self.finished = true;
+ Some(self.v)
+ }
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, P> FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An iterator over subslices separated by elements that match a predicate
+/// function. Unlike `Split`, it contains the matched part as a terminator
+/// of the subslice.
+///
+/// This struct is created by the [`split_inclusive`] method on [slices].
+///
+/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive
+/// [slices]: ../../std/primitive.slice.html
+#[unstable(feature = "split_inclusive", issue = "72360")]
+pub struct SplitInclusive<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ pub(super) v: &'a [T],
+ pub(super) pred: P,
+ pub(super) finished: bool,
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitInclusive<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SplitInclusive")
+ .field("v", &self.v)
+ .field("finished", &self.finished)
+ .finish()
+ }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<T, P> Clone for SplitInclusive<'_, T, P>
+where
+ P: Clone + FnMut(&T) -> bool,
+{
+ fn clone(&self) -> Self {
+ SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished }
+ }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, T, P> Iterator for SplitInclusive<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ type Item = &'a [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a [T]> {
+ if self.finished {
+ return None;
+ }
+
+ let idx =
+ self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len());
+ if idx == self.v.len() {
+ self.finished = true;
+ }
+ let ret = Some(&self.v[..idx]);
+ self.v = &self.v[idx..];
+ ret
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) }
+ }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a [T]> {
+ if self.finished {
+ return None;
+ }
+
+ // The last index of self.v is already checked and found to match
+ // by the last iteration, so we start searching a new match
+ // one index to the left.
+ let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] };
+ let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0);
+ if idx == 0 {
+ self.finished = true;
+ }
+ let ret = Some(&self.v[idx..]);
+ self.v = &self.v[..idx];
+ ret
+ }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<T, P> FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An iterator over the mutable subslices of the vector which are separated
+/// by elements that match `pred`.
+///
+/// This struct is created by the [`split_mut`] method on [slices].
+///
+/// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SplitMut<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ pub(super) v: &'a mut [T],
+ pub(super) pred: P,
+ pub(super) finished: bool,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitMut<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish()
+ }
+}
+
+impl<'a, T, P> SplitIter for SplitMut<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ #[inline]
+ fn finish(&mut self) -> Option<&'a mut [T]> {
+ if self.finished {
+ None
+ } else {
+ self.finished = true;
+ Some(mem::replace(&mut self.v, &mut []))
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, P> Iterator for SplitMut<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ type Item = &'a mut [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a mut [T]> {
+ if self.finished {
+ return None;
+ }
+
+ let idx_opt = {
+ // work around borrowck limitations
+ let pred = &mut self.pred;
+ self.v.iter().position(|x| (*pred)(x))
+ };
+ match idx_opt {
+ None => self.finish(),
+ Some(idx) => {
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(idx);
+ self.v = &mut tail[1..];
+ Some(head)
+ }
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.finished {
+ (0, Some(0))
+ } else {
+ // if the predicate doesn't match anything, we yield one slice
+ // if it matches every element, we yield len+1 empty slices.
+ (1, Some(self.v.len() + 1))
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a mut [T]> {
+ if self.finished {
+ return None;
+ }
+
+ let idx_opt = {
+ // work around borrowck limitations
+ let pred = &mut self.pred;
+ self.v.iter().rposition(|x| (*pred)(x))
+ };
+ match idx_opt {
+ None => self.finish(),
+ Some(idx) => {
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(idx);
+ self.v = head;
+ Some(&mut tail[1..])
+ }
+ }
+ }
+}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T, P> FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An iterator over the mutable subslices of the vector which are separated
+/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched
+/// parts in the ends of the subslices.
+///
+/// This struct is created by the [`split_inclusive_mut`] method on [slices].
+///
+/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut
+/// [slices]: ../../std/primitive.slice.html
+#[unstable(feature = "split_inclusive", issue = "72360")]
+pub struct SplitInclusiveMut<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ pub(super) v: &'a mut [T],
+ pub(super) pred: P,
+ pub(super) finished: bool,
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitInclusiveMut<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SplitInclusiveMut")
+ .field("v", &self.v)
+ .field("finished", &self.finished)
+ .finish()
+ }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ type Item = &'a mut [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a mut [T]> {
+ if self.finished {
+ return None;
+ }
+
+ let idx_opt = {
+ // work around borrowck limitations
+ let pred = &mut self.pred;
+ self.v.iter().position(|x| (*pred)(x))
+ };
+ let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len());
+ if idx == self.v.len() {
+ self.finished = true;
+ }
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(idx);
+ self.v = tail;
+ Some(head)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.finished {
+ (0, Some(0))
+ } else {
+ // if the predicate doesn't match anything, we yield one slice
+ // if it matches every element, we yield len+1 empty slices.
+ (1, Some(self.v.len() + 1))
+ }
+ }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a mut [T]> {
+ if self.finished {
+ return None;
+ }
+
+ let idx_opt = if self.v.is_empty() {
+ None
+ } else {
+ // work around borrowck limitations
+ let pred = &mut self.pred;
+
+ // The last index of self.v is already checked and found to match
+ // by the last iteration, so we start searching a new match
+ // one index to the left.
+ let remainder = &self.v[..(self.v.len() - 1)];
+ remainder.iter().rposition(|x| (*pred)(x))
+ };
+ let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0);
+ if idx == 0 {
+ self.finished = true;
+ }
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(idx);
+ self.v = head;
+ Some(tail)
+ }
+}
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+impl<T, P> FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An iterator over subslices separated by elements that match a predicate
+/// function, starting from the end of the slice.
+///
+/// This struct is created by the [`rsplit`] method on [slices].
+///
+/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`?
+pub struct RSplit<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ pub(super) inner: Split<'a, T, P>,
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<T: fmt::Debug, P> fmt::Debug for RSplit<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RSplit")
+ .field("v", &self.inner.v)
+ .field("finished", &self.inner.finished)
+ .finish()
+ }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> Iterator for RSplit<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ type Item = &'a [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a [T]> {
+ self.inner.next_back()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a [T]> {
+ self.inner.next()
+ }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> SplitIter for RSplit<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ #[inline]
+ fn finish(&mut self) -> Option<&'a [T]> {
+ self.inner.finish()
+ }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<T, P> FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An iterator over the subslices of the vector which are separated
+/// by elements that match `pred`, starting from the end of the slice.
+///
+/// This struct is created by the [`rsplit_mut`] method on [slices].
+///
+/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+pub struct RSplitMut<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ pub(super) inner: SplitMut<'a, T, P>,
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<T: fmt::Debug, P> fmt::Debug for RSplitMut<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RSplitMut")
+ .field("v", &self.inner.v)
+ .field("finished", &self.inner.finished)
+ .finish()
+ }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> SplitIter for RSplitMut<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ #[inline]
+ fn finish(&mut self) -> Option<&'a mut [T]> {
+ self.inner.finish()
+ }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> Iterator for RSplitMut<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ type Item = &'a mut [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a mut [T]> {
+ self.inner.next_back()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a mut [T]> {
+ self.inner.next()
+ }
+}
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<T, P> FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
+
+/// An private iterator over subslices separated by elements that
+/// match a predicate function, splitting at most a fixed number of
+/// times.
+#[derive(Debug)]
+pub(super) struct GenericSplitN<I> {
+ pub(super) iter: I,
+ pub(super) count: usize,
+}
+
+impl<T, I: SplitIter<Item = T>> Iterator for GenericSplitN<I> {
+ type Item = T;
+
+ #[inline]
+ fn next(&mut self) -> Option<T> {
+ match self.count {
+ 0 => None,
+ 1 => {
+ self.count -= 1;
+ self.iter.finish()
+ }
+ _ => {
+ self.count -= 1;
+ self.iter.next()
+ }
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let (lower, upper_opt) = self.iter.size_hint();
+ (lower, upper_opt.map(|upper| cmp::min(self.count, upper)))
+ }
+}
+
+/// An iterator over subslices separated by elements that match a predicate
+/// function, limited to a given number of splits.
+///
+/// This struct is created by the [`splitn`] method on [slices].
+///
+/// [`splitn`]: ../../std/primitive.slice.html#method.splitn
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SplitN<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ pub(super) inner: GenericSplitN<Split<'a, T, P>>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitN<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SplitN").field("inner", &self.inner).finish()
+ }
+}
+
+/// An iterator over subslices separated by elements that match a
+/// predicate function, limited to a given number of splits, starting
+/// from the end of the slice.
+///
+/// This struct is created by the [`rsplitn`] method on [slices].
+///
+/// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct RSplitN<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ pub(super) inner: GenericSplitN<RSplit<'a, T, P>>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for RSplitN<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RSplitN").field("inner", &self.inner).finish()
+ }
+}
+
+/// An iterator over subslices separated by elements that match a predicate
+/// function, limited to a given number of splits.
+///
+/// This struct is created by the [`splitn_mut`] method on [slices].
+///
+/// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct SplitNMut<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ pub(super) inner: GenericSplitN<SplitMut<'a, T, P>>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitNMut<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("SplitNMut").field("inner", &self.inner).finish()
+ }
+}
+
+/// An iterator over subslices separated by elements that match a
+/// predicate function, limited to a given number of splits, starting
+/// from the end of the slice.
+///
+/// This struct is created by the [`rsplitn_mut`] method on [slices].
+///
+/// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut
+/// [slices]: ../../std/primitive.slice.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct RSplitNMut<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ pub(super) inner: GenericSplitN<RSplitMut<'a, T, P>>,
+}
+
+#[stable(feature = "core_impl_debug", since = "1.9.0")]
+impl<T: fmt::Debug, P> fmt::Debug for RSplitNMut<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("RSplitNMut").field("inner", &self.inner).finish()
+ }
+}
+
+forward_iterator! { SplitN: T, &'a [T] }
+forward_iterator! { RSplitN: T, &'a [T] }
+forward_iterator! { SplitNMut: T, &'a mut [T] }
+forward_iterator! { RSplitNMut: T, &'a mut [T] }
+
+/// An iterator over overlapping subslices of length `size`.
+///
+/// This struct is created by the [`windows`] method on [slices].
+///
+/// [`windows`]: ../../std/primitive.slice.html#method.windows
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Windows<'a, T: 'a> {
+ pub(super) v: &'a [T],
+ pub(super) size: usize,
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Clone for Windows<'_, T> {
+ fn clone(&self) -> Self {
+ Windows { v: self.v, size: self.size }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> Iterator for Windows<'a, T> {
+ type Item = &'a [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a [T]> {
+ if self.size > self.v.len() {
+ None
+ } else {
+ let ret = Some(&self.v[..self.size]);
+ self.v = &self.v[1..];
+ ret
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.size > self.v.len() {
+ (0, Some(0))
+ } else {
+ let size = self.v.len() - self.size + 1;
+ (size, Some(size))
+ }
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ let (end, overflow) = self.size.overflowing_add(n);
+ if end > self.v.len() || overflow {
+ self.v = &[];
+ None
+ } else {
+ let nth = &self.v[n..end];
+ self.v = &self.v[n + 1..];
+ Some(nth)
+ }
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ if self.size > self.v.len() {
+ None
+ } else {
+ let start = self.v.len() - self.size;
+ Some(&self.v[start..])
+ }
+ }
+
+ #[doc(hidden)]
+ unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+ // SAFETY: since the caller guarantees that `i` is in bounds,
+ // which means that `i` cannot overflow an `isize`, and the
+ // slice created by `from_raw_parts` is a subslice of `self.v`
+ // thus is guaranteed to be valid for the lifetime `'a` of `self.v`.
+ unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> DoubleEndedIterator for Windows<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a [T]> {
+ if self.size > self.v.len() {
+ None
+ } else {
+ let ret = Some(&self.v[self.v.len() - self.size..]);
+ self.v = &self.v[..self.v.len() - 1];
+ ret
+ }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let (end, overflow) = self.v.len().overflowing_sub(n);
+ if end < self.size || overflow {
+ self.v = &[];
+ None
+ } else {
+ let ret = &self.v[end - self.size..end];
+ self.v = &self.v[..end - 1];
+ Some(ret)
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> ExactSizeIterator for Windows<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for Windows<'_, T> {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for Windows<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
+/// time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last slice
+/// of the iteration will be the remainder.
+///
+/// This struct is created by the [`chunks`] method on [slices].
+///
+/// [`chunks`]: ../../std/primitive.slice.html#method.chunks
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Chunks<'a, T: 'a> {
+ pub(super) v: &'a [T],
+ pub(super) chunk_size: usize,
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Clone for Chunks<'_, T> {
+ fn clone(&self) -> Self {
+ Chunks { v: self.v, chunk_size: self.chunk_size }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> Iterator for Chunks<'a, T> {
+ type Item = &'a [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a [T]> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let chunksz = cmp::min(self.v.len(), self.chunk_size);
+ let (fst, snd) = self.v.split_at(chunksz);
+ self.v = snd;
+ Some(fst)
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.v.is_empty() {
+ (0, Some(0))
+ } else {
+ let n = self.v.len() / self.chunk_size;
+ let rem = self.v.len() % self.chunk_size;
+ let n = if rem > 0 { n + 1 } else { n };
+ (n, Some(n))
+ }
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ let (start, overflow) = n.overflowing_mul(self.chunk_size);
+ if start >= self.v.len() || overflow {
+ self.v = &[];
+ None
+ } else {
+ let end = match start.checked_add(self.chunk_size) {
+ Some(sum) => cmp::min(self.v.len(), sum),
+ None => self.v.len(),
+ };
+ let nth = &self.v[start..end];
+ self.v = &self.v[end..];
+ Some(nth)
+ }
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
+ Some(&self.v[start..])
+ }
+ }
+
+ #[doc(hidden)]
+ unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+ let start = idx * self.chunk_size;
+ let end = match start.checked_add(self.chunk_size) {
+ None => self.v.len(),
+ Some(end) => cmp::min(end, self.v.len()),
+ };
+ // SAFETY: the caller guarantees that `i` is in bounds,
+ // which means that `start` must be in bounds of the
+ // underlying `self.v` slice, and we made sure that `end`
+ // is also in bounds of `self.v`. Thus, `start` cannot overflow
+ // an `isize`, and the slice constructed by `from_raw_parts`
+ // is a subslice of `self.v` which is guaranteed to be valid
+ // for the lifetime `'a` of `self.v`.
+ unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> DoubleEndedIterator for Chunks<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a [T]> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let remainder = self.v.len() % self.chunk_size;
+ let chunksz = if remainder != 0 { remainder } else { self.chunk_size };
+ let (fst, snd) = self.v.split_at(self.v.len() - chunksz);
+ self.v = fst;
+ Some(snd)
+ }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let len = self.len();
+ if n >= len {
+ self.v = &[];
+ None
+ } else {
+ let start = (len - 1 - n) * self.chunk_size;
+ let end = match start.checked_add(self.chunk_size) {
+ Some(res) => cmp::min(res, self.v.len()),
+ None => self.v.len(),
+ };
+ let nth_back = &self.v[start..end];
+ self.v = &self.v[..start];
+ Some(nth_back)
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> ExactSizeIterator for Chunks<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for Chunks<'_, T> {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for Chunks<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
+/// elements at a time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last slice
+/// of the iteration will be the remainder.
+///
+/// This struct is created by the [`chunks_mut`] method on [slices].
+///
+/// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct ChunksMut<'a, T: 'a> {
+ pub(super) v: &'a mut [T],
+ pub(super) chunk_size: usize,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> Iterator for ChunksMut<'a, T> {
+ type Item = &'a mut [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a mut [T]> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let sz = cmp::min(self.v.len(), self.chunk_size);
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(sz);
+ self.v = tail;
+ Some(head)
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.v.is_empty() {
+ (0, Some(0))
+ } else {
+ let n = self.v.len() / self.chunk_size;
+ let rem = self.v.len() % self.chunk_size;
+ let n = if rem > 0 { n + 1 } else { n };
+ (n, Some(n))
+ }
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
+ let (start, overflow) = n.overflowing_mul(self.chunk_size);
+ if start >= self.v.len() || overflow {
+ self.v = &mut [];
+ None
+ } else {
+ let end = match start.checked_add(self.chunk_size) {
+ Some(sum) => cmp::min(self.v.len(), sum),
+ None => self.v.len(),
+ };
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(end);
+ let (_, nth) = head.split_at_mut(start);
+ self.v = tail;
+ Some(nth)
+ }
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
+ Some(&mut self.v[start..])
+ }
+ }
+
+ #[doc(hidden)]
+ unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+ let start = idx * self.chunk_size;
+ let end = match start.checked_add(self.chunk_size) {
+ None => self.v.len(),
+ Some(end) => cmp::min(end, self.v.len()),
+ };
+ // SAFETY: see comments for `Chunks::get_unchecked`.
+ //
+ // Also note that the caller also guarantees that we're never called
+ // with the same index again, and that no other methods that will
+ // access this subslice are called, so it is valid for the returned
+ // slice to be mutable.
+ unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a mut [T]> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let remainder = self.v.len() % self.chunk_size;
+ let sz = if remainder != 0 { remainder } else { self.chunk_size };
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let tmp_len = tmp.len();
+ let (head, tail) = tmp.split_at_mut(tmp_len - sz);
+ self.v = head;
+ Some(tail)
+ }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let len = self.len();
+ if n >= len {
+ self.v = &mut [];
+ None
+ } else {
+ let start = (len - 1 - n) * self.chunk_size;
+ let end = match start.checked_add(self.chunk_size) {
+ Some(res) => cmp::min(res, self.v.len()),
+ None => self.v.len(),
+ };
+ let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+ let (head, nth_back) = temp.split_at_mut(start);
+ self.v = head;
+ Some(nth_back)
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> ExactSizeIterator for ChunksMut<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for ChunksMut<'_, T> {}
+
+#[stable(feature = "fused", since = "1.26.0")]
+impl<T> FusedIterator for ChunksMut<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
+/// time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last
+/// up to `chunk_size-1` elements will be omitted but can be retrieved from
+/// the [`remainder`] function from the iterator.
+///
+/// This struct is created by the [`chunks_exact`] method on [slices].
+///
+/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact
+/// [`remainder`]: ChunksExact::remainder
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+pub struct ChunksExact<'a, T: 'a> {
+ pub(super) v: &'a [T],
+ pub(super) rem: &'a [T],
+ pub(super) chunk_size: usize,
+}
+
+impl<'a, T> ChunksExact<'a, T> {
+ /// Returns the remainder of the original slice that is not going to be
+ /// returned by the iterator. The returned slice has at most `chunk_size-1`
+ /// elements.
+ #[stable(feature = "chunks_exact", since = "1.31.0")]
+ pub fn remainder(&self) -> &'a [T] {
+ self.rem
+ }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<T> Clone for ChunksExact<'_, T> {
+ fn clone(&self) -> Self {
+ ChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size }
+ }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<'a, T> Iterator for ChunksExact<'a, T> {
+ type Item = &'a [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a [T]> {
+ if self.v.len() < self.chunk_size {
+ None
+ } else {
+ let (fst, snd) = self.v.split_at(self.chunk_size);
+ self.v = snd;
+ Some(fst)
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let n = self.v.len() / self.chunk_size;
+ (n, Some(n))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ let (start, overflow) = n.overflowing_mul(self.chunk_size);
+ if start >= self.v.len() || overflow {
+ self.v = &[];
+ None
+ } else {
+ let (_, snd) = self.v.split_at(start);
+ self.v = snd;
+ self.next()
+ }
+ }
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
+
+ #[doc(hidden)]
+ unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+ let start = idx * self.chunk_size;
+ // SAFETY: mostly identical to `Chunks::get_unchecked`.
+ unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
+ }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a [T]> {
+ if self.v.len() < self.chunk_size {
+ None
+ } else {
+ let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size);
+ self.v = fst;
+ Some(snd)
+ }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let len = self.len();
+ if n >= len {
+ self.v = &[];
+ None
+ } else {
+ let start = (len - 1 - n) * self.chunk_size;
+ let end = start + self.chunk_size;
+ let nth_back = &self.v[start..end];
+ self.v = &self.v[..start];
+ Some(nth_back)
+ }
+ }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<T> ExactSizeIterator for ChunksExact<'_, T> {
+ fn is_empty(&self) -> bool {
+ self.v.is_empty()
+ }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for ChunksExact<'_, T> {}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<T> FusedIterator for ChunksExact<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
+/// elements at a time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last up to
+/// `chunk_size-1` elements will be omitted but can be retrieved from the
+/// [`into_remainder`] function from the iterator.
+///
+/// This struct is created by the [`chunks_exact_mut`] method on [slices].
+///
+/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut
+/// [`into_remainder`]: ChunksExactMut::into_remainder
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+pub struct ChunksExactMut<'a, T: 'a> {
+ pub(super) v: &'a mut [T],
+ pub(super) rem: &'a mut [T],
+ pub(super) chunk_size: usize,
+}
+
+impl<'a, T> ChunksExactMut<'a, T> {
+ /// Returns the remainder of the original slice that is not going to be
+ /// returned by the iterator. The returned slice has at most `chunk_size-1`
+ /// elements.
+ #[stable(feature = "chunks_exact", since = "1.31.0")]
+ pub fn into_remainder(self) -> &'a mut [T] {
+ self.rem
+ }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<'a, T> Iterator for ChunksExactMut<'a, T> {
+ type Item = &'a mut [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a mut [T]> {
+ if self.v.len() < self.chunk_size {
+ None
+ } else {
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(self.chunk_size);
+ self.v = tail;
+ Some(head)
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let n = self.v.len() / self.chunk_size;
+ (n, Some(n))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
+ let (start, overflow) = n.overflowing_mul(self.chunk_size);
+ if start >= self.v.len() || overflow {
+ self.v = &mut [];
+ None
+ } else {
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (_, snd) = tmp.split_at_mut(start);
+ self.v = snd;
+ self.next()
+ }
+ }
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
+
+ #[doc(hidden)]
+ unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+ let start = idx * self.chunk_size;
+ // SAFETY: see comments for `ChunksMut::get_unchecked`.
+ unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
+ }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a mut [T]> {
+ if self.v.len() < self.chunk_size {
+ None
+ } else {
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let tmp_len = tmp.len();
+ let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
+ self.v = head;
+ Some(tail)
+ }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let len = self.len();
+ if n >= len {
+ self.v = &mut [];
+ None
+ } else {
+ let start = (len - 1 - n) * self.chunk_size;
+ let end = start + self.chunk_size;
+ let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+ let (head, nth_back) = temp.split_at_mut(start);
+ self.v = head;
+ Some(nth_back)
+ }
+ }
+}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<T> ExactSizeIterator for ChunksExactMut<'_, T> {
+ fn is_empty(&self) -> bool {
+ self.v.is_empty()
+ }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for ChunksExactMut<'_, T> {}
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+impl<T> FusedIterator for ChunksExactMut<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+/// A windowed iterator over a slice in overlapping chunks (`N` elements at a
+/// time), starting at the beginning of the slice
+///
+/// This struct is created by the [`array_windows`] method on [slices].
+///
+/// [`array_windows`]: ../../std/primitive.slice.html#method.array_windows
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug, Clone, Copy)]
+#[unstable(feature = "array_windows", issue = "75027")]
+pub struct ArrayWindows<'a, T: 'a, const N: usize> {
+ pub(crate) slice_head: *const T,
+ pub(crate) num: usize,
+ pub(crate) marker: marker::PhantomData<&'a [T; N]>,
+}
+
+#[unstable(feature = "array_windows", issue = "75027")]
+impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> {
+ type Item = &'a [T; N];
+
+ #[inline]
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.num == 0 {
+ return None;
+ }
+ // SAFETY:
+ // This is safe because it's indexing into a slice guaranteed to be length > N.
+ let ret = unsafe { &*self.slice_head.cast::<[T; N]>() };
+ // SAFETY: Guaranteed that there are at least 1 item remaining otherwise
+ // earlier branch would've been hit
+ self.slice_head = unsafe { self.slice_head.add(1) };
+
+ self.num -= 1;
+ Some(ret)
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.num, Some(self.num))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.num
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ if self.num <= n {
+ self.num = 0;
+ return None;
+ }
+ // SAFETY:
+ // This is safe because it's indexing into a slice guaranteed to be length > N.
+ let ret = unsafe { &*self.slice_head.add(n).cast::<[T; N]>() };
+ // SAFETY: Guaranteed that there are at least n items remaining
+ self.slice_head = unsafe { self.slice_head.add(n + 1) };
+
+ self.num -= n + 1;
+ Some(ret)
+ }
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.nth(self.num.checked_sub(1)?)
+ }
+}
+
+#[unstable(feature = "array_windows", issue = "75027")]
+impl<'a, T, const N: usize> DoubleEndedIterator for ArrayWindows<'a, T, N> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a [T; N]> {
+ if self.num == 0 {
+ return None;
+ }
+ // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing.
+ let ret = unsafe { &*self.slice_head.add(self.num - 1).cast::<[T; N]>() };
+ self.num -= 1;
+ Some(ret)
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<&'a [T; N]> {
+ if self.num <= n {
+ self.num = 0;
+ return None;
+ }
+ // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing.
+ let ret = unsafe { &*self.slice_head.add(self.num - (n + 1)).cast::<[T; N]>() };
+ self.num -= n + 1;
+ Some(ret)
+ }
+}
+
+#[unstable(feature = "array_windows", issue = "75027")]
+impl<T, const N: usize> ExactSizeIterator for ArrayWindows<'_, T, N> {
+ fn is_empty(&self) -> bool {
+ self.num == 0
+ }
+}
+
+/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a
+/// time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last
+/// up to `N-1` elements will be omitted but can be retrieved from
+/// the [`remainder`] function from the iterator.
+///
+/// This struct is created by the [`array_chunks`] method on [slices].
+///
+/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks
+/// [`remainder`]: ArrayChunks::remainder
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[unstable(feature = "array_chunks", issue = "74985")]
+pub struct ArrayChunks<'a, T: 'a, const N: usize> {
+ pub(super) iter: Iter<'a, [T; N]>,
+ pub(super) rem: &'a [T],
+}
+
+impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
+ /// Returns the remainder of the original slice that is not going to be
+ /// returned by the iterator. The returned slice has at most `N-1`
+ /// elements.
+ #[unstable(feature = "array_chunks", issue = "74985")]
+ pub fn remainder(&self) -> &'a [T] {
+ self.rem
+ }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<T, const N: usize> Clone for ArrayChunks<'_, T, N> {
+ fn clone(&self) -> Self {
+ ArrayChunks { iter: self.iter.clone(), rem: self.rem }
+ }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> {
+ type Item = &'a [T; N];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a [T; N]> {
+ self.iter.next()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.iter.count()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ self.iter.nth(n)
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ self.iter.last()
+ }
+
+ unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] {
+ // SAFETY: The safety guarantees of `get_unchecked` are transferred to
+ // the caller.
+ unsafe { self.iter.get_unchecked(i) }
+ }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a [T; N]> {
+ self.iter.next_back()
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ self.iter.nth_back(n)
+ }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<T, const N: usize> ExactSizeIterator for ArrayChunks<'_, T, N> {
+ fn is_empty(&self) -> bool {
+ self.iter.is_empty()
+ }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T, const N: usize> TrustedLen for ArrayChunks<'_, T, N> {}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {}
+
+#[doc(hidden)]
+#[unstable(feature = "array_chunks", issue = "74985")]
+unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements
+/// at a time), starting at the beginning of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last
+/// up to `N-1` elements will be omitted but can be retrieved from
+/// the [`into_remainder`] function from the iterator.
+///
+/// This struct is created by the [`array_chunks_mut`] method on [slices].
+///
+/// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut
+/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[unstable(feature = "array_chunks", issue = "74985")]
+pub struct ArrayChunksMut<'a, T: 'a, const N: usize> {
+ pub(super) iter: IterMut<'a, [T; N]>,
+ pub(super) rem: &'a mut [T],
+}
+
+impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
+ /// Returns the remainder of the original slice that is not going to be
+ /// returned by the iterator. The returned slice has at most `N-1`
+ /// elements.
+ #[unstable(feature = "array_chunks", issue = "74985")]
+ pub fn into_remainder(self) -> &'a mut [T] {
+ self.rem
+ }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> {
+ type Item = &'a mut [T; N];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a mut [T; N]> {
+ self.iter.next()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.iter.count()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ self.iter.nth(n)
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ self.iter.last()
+ }
+
+ unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] {
+ // SAFETY: The safety guarantees of `get_unchecked` are transferred to
+ // the caller.
+ unsafe { self.iter.get_unchecked(i) }
+ }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a mut [T; N]> {
+ self.iter.next_back()
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ self.iter.nth_back(n)
+ }
+}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<T, const N: usize> ExactSizeIterator for ArrayChunksMut<'_, T, N> {
+ fn is_empty(&self) -> bool {
+ self.iter.is_empty()
+ }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T, const N: usize> TrustedLen for ArrayChunksMut<'_, T, N> {}
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+impl<T, const N: usize> FusedIterator for ArrayChunksMut<'_, T, N> {}
+
+#[doc(hidden)]
+#[unstable(feature = "array_chunks", issue = "74985")]
+unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
+/// time), starting at the end of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last slice
+/// of the iteration will be the remainder.
+///
+/// This struct is created by the [`rchunks`] method on [slices].
+///
+/// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[stable(feature = "rchunks", since = "1.31.0")]
+pub struct RChunks<'a, T: 'a> {
+ pub(super) v: &'a [T],
+ pub(super) chunk_size: usize,
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> Clone for RChunks<'_, T> {
+ fn clone(&self) -> Self {
+ RChunks { v: self.v, chunk_size: self.chunk_size }
+ }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> Iterator for RChunks<'a, T> {
+ type Item = &'a [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a [T]> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let chunksz = cmp::min(self.v.len(), self.chunk_size);
+ let (fst, snd) = self.v.split_at(self.v.len() - chunksz);
+ self.v = fst;
+ Some(snd)
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.v.is_empty() {
+ (0, Some(0))
+ } else {
+ let n = self.v.len() / self.chunk_size;
+ let rem = self.v.len() % self.chunk_size;
+ let n = if rem > 0 { n + 1 } else { n };
+ (n, Some(n))
+ }
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ let (end, overflow) = n.overflowing_mul(self.chunk_size);
+ if end >= self.v.len() || overflow {
+ self.v = &[];
+ None
+ } else {
+ // Can't underflow because of the check above
+ let end = self.v.len() - end;
+ let start = match end.checked_sub(self.chunk_size) {
+ Some(sum) => sum,
+ None => 0,
+ };
+ let nth = &self.v[start..end];
+ self.v = &self.v[0..start];
+ Some(nth)
+ }
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let rem = self.v.len() % self.chunk_size;
+ let end = if rem == 0 { self.chunk_size } else { rem };
+ Some(&self.v[0..end])
+ }
+ }
+
+ #[doc(hidden)]
+ unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+ let end = self.v.len() - idx * self.chunk_size;
+ let start = match end.checked_sub(self.chunk_size) {
+ None => 0,
+ Some(start) => start,
+ };
+ // SAFETY: mostly identical to `Chunks::get_unchecked`.
+ unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
+ }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for RChunks<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a [T]> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let remainder = self.v.len() % self.chunk_size;
+ let chunksz = if remainder != 0 { remainder } else { self.chunk_size };
+ let (fst, snd) = self.v.split_at(chunksz);
+ self.v = snd;
+ Some(fst)
+ }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let len = self.len();
+ if n >= len {
+ self.v = &[];
+ None
+ } else {
+ // can't underflow because `n < len`
+ let offset_from_end = (len - 1 - n) * self.chunk_size;
+ let end = self.v.len() - offset_from_end;
+ let start = end.saturating_sub(self.chunk_size);
+ let nth_back = &self.v[start..end];
+ self.v = &self.v[end..];
+ Some(nth_back)
+ }
+ }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> ExactSizeIterator for RChunks<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for RChunks<'_, T> {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> FusedIterator for RChunks<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
+/// elements at a time), starting at the end of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last slice
+/// of the iteration will be the remainder.
+///
+/// This struct is created by the [`rchunks_mut`] method on [slices].
+///
+/// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[stable(feature = "rchunks", since = "1.31.0")]
+pub struct RChunksMut<'a, T: 'a> {
+ pub(super) v: &'a mut [T],
+ pub(super) chunk_size: usize,
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> Iterator for RChunksMut<'a, T> {
+ type Item = &'a mut [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a mut [T]> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let sz = cmp::min(self.v.len(), self.chunk_size);
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let tmp_len = tmp.len();
+ let (head, tail) = tmp.split_at_mut(tmp_len - sz);
+ self.v = head;
+ Some(tail)
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ if self.v.is_empty() {
+ (0, Some(0))
+ } else {
+ let n = self.v.len() / self.chunk_size;
+ let rem = self.v.len() % self.chunk_size;
+ let n = if rem > 0 { n + 1 } else { n };
+ (n, Some(n))
+ }
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
+ let (end, overflow) = n.overflowing_mul(self.chunk_size);
+ if end >= self.v.len() || overflow {
+ self.v = &mut [];
+ None
+ } else {
+ // Can't underflow because of the check above
+ let end = self.v.len() - end;
+ let start = match end.checked_sub(self.chunk_size) {
+ Some(sum) => sum,
+ None => 0,
+ };
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(start);
+ let (nth, _) = tail.split_at_mut(end - start);
+ self.v = head;
+ Some(nth)
+ }
+ }
+
+ #[inline]
+ fn last(self) -> Option<Self::Item> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let rem = self.v.len() % self.chunk_size;
+ let end = if rem == 0 { self.chunk_size } else { rem };
+ Some(&mut self.v[0..end])
+ }
+ }
+
+ #[doc(hidden)]
+ unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+ let end = self.v.len() - idx * self.chunk_size;
+ let start = match end.checked_sub(self.chunk_size) {
+ None => 0,
+ Some(start) => start,
+ };
+ // SAFETY: see comments for `RChunks::get_unchecked` and `ChunksMut::get_unchecked`
+ unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
+ }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a mut [T]> {
+ if self.v.is_empty() {
+ None
+ } else {
+ let remainder = self.v.len() % self.chunk_size;
+ let sz = if remainder != 0 { remainder } else { self.chunk_size };
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(sz);
+ self.v = tail;
+ Some(head)
+ }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let len = self.len();
+ if n >= len {
+ self.v = &mut [];
+ None
+ } else {
+ // can't underflow because `n < len`
+ let offset_from_end = (len - 1 - n) * self.chunk_size;
+ let end = self.v.len() - offset_from_end;
+ let start = end.saturating_sub(self.chunk_size);
+ let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+ let (_, nth_back) = tmp.split_at_mut(start);
+ self.v = tail;
+ Some(nth_back)
+ }
+ }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> ExactSizeIterator for RChunksMut<'_, T> {}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for RChunksMut<'_, T> {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> FusedIterator for RChunksMut<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
+/// time), starting at the end of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last
+/// up to `chunk_size-1` elements will be omitted but can be retrieved from
+/// the [`remainder`] function from the iterator.
+///
+/// This struct is created by the [`rchunks_exact`] method on [slices].
+///
+/// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact
+/// [`remainder`]: ChunksExact::remainder
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[stable(feature = "rchunks", since = "1.31.0")]
+pub struct RChunksExact<'a, T: 'a> {
+ pub(super) v: &'a [T],
+ pub(super) rem: &'a [T],
+ pub(super) chunk_size: usize,
+}
+
+impl<'a, T> RChunksExact<'a, T> {
+ /// Returns the remainder of the original slice that is not going to be
+ /// returned by the iterator. The returned slice has at most `chunk_size-1`
+ /// elements.
+ #[stable(feature = "rchunks", since = "1.31.0")]
+ pub fn remainder(&self) -> &'a [T] {
+ self.rem
+ }
+}
+
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> Clone for RChunksExact<'a, T> {
+ fn clone(&self) -> RChunksExact<'a, T> {
+ RChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size }
+ }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> Iterator for RChunksExact<'a, T> {
+ type Item = &'a [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a [T]> {
+ if self.v.len() < self.chunk_size {
+ None
+ } else {
+ let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size);
+ self.v = fst;
+ Some(snd)
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let n = self.v.len() / self.chunk_size;
+ (n, Some(n))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<Self::Item> {
+ let (end, overflow) = n.overflowing_mul(self.chunk_size);
+ if end >= self.v.len() || overflow {
+ self.v = &[];
+ None
+ } else {
+ let (fst, _) = self.v.split_at(self.v.len() - end);
+ self.v = fst;
+ self.next()
+ }
+ }
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
+
+ #[doc(hidden)]
+ unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+ let end = self.v.len() - idx * self.chunk_size;
+ let start = end - self.chunk_size;
+ // SAFETY:
+ // SAFETY: mostmy identical to `Chunks::get_unchecked`.
+ unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
+ }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a [T]> {
+ if self.v.len() < self.chunk_size {
+ None
+ } else {
+ let (fst, snd) = self.v.split_at(self.chunk_size);
+ self.v = snd;
+ Some(fst)
+ }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let len = self.len();
+ if n >= len {
+ self.v = &[];
+ None
+ } else {
+ // now that we know that `n` corresponds to a chunk,
+ // none of these operations can underflow/overflow
+ let offset = (len - n) * self.chunk_size;
+ let start = self.v.len() - offset;
+ let end = start + self.chunk_size;
+ let nth_back = &self.v[start..end];
+ self.v = &self.v[end..];
+ Some(nth_back)
+ }
+ }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> {
+ fn is_empty(&self) -> bool {
+ self.v.is_empty()
+ }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for RChunksExact<'_, T> {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> FusedIterator for RChunksExact<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
+/// elements at a time), starting at the end of the slice.
+///
+/// When the slice len is not evenly divided by the chunk size, the last up to
+/// `chunk_size-1` elements will be omitted but can be retrieved from the
+/// [`into_remainder`] function from the iterator.
+///
+/// This struct is created by the [`rchunks_exact_mut`] method on [slices].
+///
+/// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut
+/// [`into_remainder`]: ChunksExactMut::into_remainder
+/// [slices]: ../../std/primitive.slice.html
+#[derive(Debug)]
+#[stable(feature = "rchunks", since = "1.31.0")]
+pub struct RChunksExactMut<'a, T: 'a> {
+ pub(super) v: &'a mut [T],
+ pub(super) rem: &'a mut [T],
+ pub(super) chunk_size: usize,
+}
+
+impl<'a, T> RChunksExactMut<'a, T> {
+ /// Returns the remainder of the original slice that is not going to be
+ /// returned by the iterator. The returned slice has at most `chunk_size-1`
+ /// elements.
+ #[stable(feature = "rchunks", since = "1.31.0")]
+ pub fn into_remainder(self) -> &'a mut [T] {
+ self.rem
+ }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> Iterator for RChunksExactMut<'a, T> {
+ type Item = &'a mut [T];
+
+ #[inline]
+ fn next(&mut self) -> Option<&'a mut [T]> {
+ if self.v.len() < self.chunk_size {
+ None
+ } else {
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let tmp_len = tmp.len();
+ let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
+ self.v = head;
+ Some(tail)
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let n = self.v.len() / self.chunk_size;
+ (n, Some(n))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ self.len()
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
+ let (end, overflow) = n.overflowing_mul(self.chunk_size);
+ if end >= self.v.len() || overflow {
+ self.v = &mut [];
+ None
+ } else {
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let tmp_len = tmp.len();
+ let (fst, _) = tmp.split_at_mut(tmp_len - end);
+ self.v = fst;
+ self.next()
+ }
+ }
+
+ #[inline]
+ fn last(mut self) -> Option<Self::Item> {
+ self.next_back()
+ }
+
+ #[doc(hidden)]
+ unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+ let end = self.v.len() - idx * self.chunk_size;
+ let start = end - self.chunk_size;
+ // SAFETY: see comments for `RChunksMut::get_unchecked`.
+ unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
+ }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<&'a mut [T]> {
+ if self.v.len() < self.chunk_size {
+ None
+ } else {
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(self.chunk_size);
+ self.v = tail;
+ Some(head)
+ }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
+ let len = self.len();
+ if n >= len {
+ self.v = &mut [];
+ None
+ } else {
+ // now that we know that `n` corresponds to a chunk,
+ // none of these operations can underflow/overflow
+ let offset = (len - n) * self.chunk_size;
+ let start = self.v.len() - offset;
+ let end = start + self.chunk_size;
+ let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
+ let (_, nth_back) = tmp.split_at_mut(start);
+ self.v = tail;
+ Some(nth_back)
+ }
+ }
+}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> ExactSizeIterator for RChunksExactMut<'_, T> {
+ fn is_empty(&self) -> bool {
+ self.v.is_empty()
+ }
+}
+
+#[unstable(feature = "trusted_len", issue = "37572")]
+unsafe impl<T> TrustedLen for RChunksExactMut<'_, T> {}
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+impl<T> FusedIterator for RChunksExactMut<'_, T> {}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
+
+#[doc(hidden)]
+#[unstable(feature = "trusted_random_access", issue = "none")]
+unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {
+ fn may_have_side_effect() -> bool {
+ false
+ }
+}
--- /dev/null
+//! Macros used by iterators of slice.
+
+// Inlining is_empty and len makes a huge performance difference
+macro_rules! is_empty {
+ // The way we encode the length of a ZST iterator, this works both for ZST
+ // and non-ZST.
+ ($self: ident) => {
+ $self.ptr.as_ptr() as *const T == $self.end
+ };
+}
+
+// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
+// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
+macro_rules! len {
+ ($self: ident) => {{
+ #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
+
+ let start = $self.ptr;
+ let size = size_from_ptr(start.as_ptr());
+ if size == 0 {
+ // This _cannot_ use `unchecked_sub` because we depend on wrapping
+ // to represent the length of long ZST slice iterators.
+ ($self.end as usize).wrapping_sub(start.as_ptr() as usize)
+ } else {
+ // We know that `start <= end`, so can do better than `offset_from`,
+ // which needs to deal in signed. By setting appropriate flags here
+ // we can tell LLVM this, which helps it remove bounds checks.
+ // SAFETY: By the type invariant, `start <= end`
+ let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) };
+ // By also telling LLVM that the pointers are apart by an exact
+ // multiple of the type size, it can optimize `len() == 0` down to
+ // `start == end` instead of `(end - start) < size`.
+ // SAFETY: By the type invariant, the pointers are aligned so the
+ // distance between them must be a multiple of pointee size
+ unsafe { exact_div(diff, size) }
+ }
+ }};
+}
+
+// The shared definition of the `Iter` and `IterMut` iterators
+macro_rules! iterator {
+ (
+ struct $name:ident -> $ptr:ty,
+ $elem:ty,
+ $raw_mut:tt,
+ {$( $mut_:tt )?},
+ {$($extra:tt)*}
+ ) => {
+ // Returns the first element and moves the start of the iterator forwards by 1.
+ // Greatly improves performance compared to an inlined function. The iterator
+ // must not be empty.
+ macro_rules! next_unchecked {
+ ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)}
+ }
+
+ // Returns the last element and moves the end of the iterator backwards by 1.
+ // Greatly improves performance compared to an inlined function. The iterator
+ // must not be empty.
+ macro_rules! next_back_unchecked {
+ ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)}
+ }
+
+ // Shrinks the iterator when T is a ZST, by moving the end of the iterator
+ // backwards by `n`. `n` must not exceed `self.len()`.
+ macro_rules! zst_shrink {
+ ($self: ident, $n: ident) => {
+ $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T;
+ }
+ }
+
+ impl<'a, T> $name<'a, T> {
+ // Helper function for creating a slice from the iterator.
+ #[inline(always)]
+ fn make_slice(&self) -> &'a [T] {
+ // SAFETY: the iterator was created from a slice with pointer
+ // `self.ptr` and length `len!(self)`. This guarantees that all
+ // the prerequisites for `from_raw_parts` are fulfilled.
+ unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) }
+ }
+
+ // Helper function for moving the start of the iterator forwards by `offset` elements,
+ // returning the old start.
+ // Unsafe because the offset must not exceed `self.len()`.
+ #[inline(always)]
+ unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T {
+ if mem::size_of::<T>() == 0 {
+ zst_shrink!(self, offset);
+ self.ptr.as_ptr()
+ } else {
+ let old = self.ptr.as_ptr();
+ // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
+ // so this new pointer is inside `self` and thus guaranteed to be non-null.
+ self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) };
+ old
+ }
+ }
+
+ // Helper function for moving the end of the iterator backwards by `offset` elements,
+ // returning the new end.
+ // Unsafe because the offset must not exceed `self.len()`.
+ #[inline(always)]
+ unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T {
+ if mem::size_of::<T>() == 0 {
+ zst_shrink!(self, offset);
+ self.ptr.as_ptr()
+ } else {
+ // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
+ // which is guaranteed to not overflow an `isize`. Also, the resulting pointer
+ // is in bounds of `slice`, which fulfills the other requirements for `offset`.
+ self.end = unsafe { self.end.offset(-offset) };
+ self.end
+ }
+ }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl<T> ExactSizeIterator for $name<'_, T> {
+ #[inline(always)]
+ fn len(&self) -> usize {
+ len!(self)
+ }
+
+ #[inline(always)]
+ fn is_empty(&self) -> bool {
+ is_empty!(self)
+ }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl<'a, T> Iterator for $name<'a, T> {
+ type Item = $elem;
+
+ #[inline]
+ fn next(&mut self) -> Option<$elem> {
+ // could be implemented with slices, but this avoids bounds checks
+
+ // SAFETY: `assume` calls are safe since a slice's start pointer
+ // must be non-null, and slices over non-ZSTs must also have a
+ // non-null end pointer. The call to `next_unchecked!` is safe
+ // since we check if the iterator is empty first.
+ unsafe {
+ assume(!self.ptr.as_ptr().is_null());
+ if mem::size_of::<T>() != 0 {
+ assume(!self.end.is_null());
+ }
+ if is_empty!(self) {
+ None
+ } else {
+ Some(next_unchecked!(self))
+ }
+ }
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let exact = len!(self);
+ (exact, Some(exact))
+ }
+
+ #[inline]
+ fn count(self) -> usize {
+ len!(self)
+ }
+
+ #[inline]
+ fn nth(&mut self, n: usize) -> Option<$elem> {
+ if n >= len!(self) {
+ // This iterator is now empty.
+ if mem::size_of::<T>() == 0 {
+ // We have to do it this way as `ptr` may never be 0, but `end`
+ // could be (due to wrapping).
+ self.end = self.ptr.as_ptr();
+ } else {
+ // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
+ unsafe {
+ self.ptr = NonNull::new_unchecked(self.end as *mut T);
+ }
+ }
+ return None;
+ }
+ // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs.
+ unsafe {
+ self.post_inc_start(n as isize);
+ Some(next_unchecked!(self))
+ }
+ }
+
+ #[inline]
+ fn last(mut self) -> Option<$elem> {
+ self.next_back()
+ }
+
+ // We override the default implementation, which uses `try_fold`,
+ // because this simple implementation generates less LLVM IR and is
+ // faster to compile.
+ #[inline]
+ fn for_each<F>(mut self, mut f: F)
+ where
+ Self: Sized,
+ F: FnMut(Self::Item),
+ {
+ while let Some(x) = self.next() {
+ f(x);
+ }
+ }
+
+ // We override the default implementation, which uses `try_fold`,
+ // because this simple implementation generates less LLVM IR and is
+ // faster to compile.
+ #[inline]
+ fn all<F>(&mut self, mut f: F) -> bool
+ where
+ Self: Sized,
+ F: FnMut(Self::Item) -> bool,
+ {
+ while let Some(x) = self.next() {
+ if !f(x) {
+ return false;
+ }
+ }
+ true
+ }
+
+ // We override the default implementation, which uses `try_fold`,
+ // because this simple implementation generates less LLVM IR and is
+ // faster to compile.
+ #[inline]
+ fn any<F>(&mut self, mut f: F) -> bool
+ where
+ Self: Sized,
+ F: FnMut(Self::Item) -> bool,
+ {
+ while let Some(x) = self.next() {
+ if f(x) {
+ return true;
+ }
+ }
+ false
+ }
+
+ // We override the default implementation, which uses `try_fold`,
+ // because this simple implementation generates less LLVM IR and is
+ // faster to compile.
+ #[inline]
+ fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
+ where
+ Self: Sized,
+ P: FnMut(&Self::Item) -> bool,
+ {
+ while let Some(x) = self.next() {
+ if predicate(&x) {
+ return Some(x);
+ }
+ }
+ None
+ }
+
+ // We override the default implementation, which uses `try_fold`,
+ // because this simple implementation generates less LLVM IR and is
+ // faster to compile.
+ #[inline]
+ fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
+ where
+ Self: Sized,
+ F: FnMut(Self::Item) -> Option<B>,
+ {
+ while let Some(x) = self.next() {
+ if let Some(y) = f(x) {
+ return Some(y);
+ }
+ }
+ None
+ }
+
+ // We override the default implementation, which uses `try_fold`,
+ // because this simple implementation generates less LLVM IR and is
+ // faster to compile. Also, the `assume` avoids a bounds check.
+ #[inline]
+ #[rustc_inherit_overflow_checks]
+ fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
+ Self: Sized,
+ P: FnMut(Self::Item) -> bool,
+ {
+ let n = len!(self);
+ let mut i = 0;
+ while let Some(x) = self.next() {
+ if predicate(x) {
+ // SAFETY: we are guaranteed to be in bounds by the loop invariant:
+ // when `i >= n`, `self.next()` returns `None` and the loop breaks.
+ unsafe { assume(i < n) };
+ return Some(i);
+ }
+ i += 1;
+ }
+ None
+ }
+
+ // We override the default implementation, which uses `try_fold`,
+ // because this simple implementation generates less LLVM IR and is
+ // faster to compile. Also, the `assume` avoids a bounds check.
+ #[inline]
+ fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
+ P: FnMut(Self::Item) -> bool,
+ Self: Sized + ExactSizeIterator + DoubleEndedIterator
+ {
+ let n = len!(self);
+ let mut i = n;
+ while let Some(x) = self.next_back() {
+ i -= 1;
+ if predicate(x) {
+ // SAFETY: `i` must be lower than `n` since it starts at `n`
+ // and is only decreasing.
+ unsafe { assume(i < n) };
+ return Some(i);
+ }
+ }
+ None
+ }
+
+ #[doc(hidden)]
+ unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
+ // SAFETY: the caller must guarantee that `i` is in bounds of
+ // the underlying slice, so `i` cannot overflow an `isize`, and
+ // the returned references is guaranteed to refer to an element
+ // of the slice and thus guaranteed to be valid.
+ //
+ // Also note that the caller also guarantees that we're never
+ // called with the same index again, and that no other methods
+ // that will access this subslice are called, so it is valid
+ // for the returned reference to be mutable in the case of
+ // `IterMut`
+ unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) }
+ }
+
+ $($extra)*
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl<'a, T> DoubleEndedIterator for $name<'a, T> {
+ #[inline]
+ fn next_back(&mut self) -> Option<$elem> {
+ // could be implemented with slices, but this avoids bounds checks
+
+ // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null,
+ // and slices over non-ZSTs must also have a non-null end pointer.
+ // The call to `next_back_unchecked!` is safe since we check if the iterator is
+ // empty first.
+ unsafe {
+ assume(!self.ptr.as_ptr().is_null());
+ if mem::size_of::<T>() != 0 {
+ assume(!self.end.is_null());
+ }
+ if is_empty!(self) {
+ None
+ } else {
+ Some(next_back_unchecked!(self))
+ }
+ }
+ }
+
+ #[inline]
+ fn nth_back(&mut self, n: usize) -> Option<$elem> {
+ if n >= len!(self) {
+ // This iterator is now empty.
+ self.end = self.ptr.as_ptr();
+ return None;
+ }
+ // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
+ unsafe {
+ self.pre_dec_end(n as isize);
+ Some(next_back_unchecked!(self))
+ }
+ }
+ }
+
+ #[stable(feature = "fused", since = "1.26.0")]
+ impl<T> FusedIterator for $name<'_, T> {}
+
+ #[unstable(feature = "trusted_len", issue = "37572")]
+ unsafe impl<T> TrustedLen for $name<'_, T> {}
+ }
+}
+
+macro_rules! forward_iterator {
+ ($name:ident: $elem:ident, $iter_of:ty) => {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl<'a, $elem, P> Iterator for $name<'a, $elem, P>
+ where
+ P: FnMut(&T) -> bool,
+ {
+ type Item = $iter_of;
+
+ #[inline]
+ fn next(&mut self) -> Option<$iter_of> {
+ self.inner.next()
+ }
+
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+ }
+
+ #[stable(feature = "fused", since = "1.26.0")]
+ impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {}
+ };
+}
#![stable(feature = "rust1", since = "1.0.0")]
-// How this module is organized.
-//
-// The library infrastructure for slices is fairly messy. There's
-// a lot of stuff defined here. Let's keep it clean.
-//
-// The layout of this file is thus:
-//
-// * Inherent methods. This is where most of the slice API resides.
-// * Implementations of a few common traits with important slice ops.
-// * Definitions of a bunch of iterators.
-// * Free functions.
-// * The `raw` and `bytes` submodules.
-// * Boilerplate trait implementations.
-
-use crate::cmp;
use crate::cmp::Ordering::{self, Equal, Greater, Less};
-use crate::fmt;
-use crate::intrinsics::{assume, exact_div, is_aligned_and_not_null, unchecked_sub};
-use crate::iter::*;
-use crate::marker::{self, Copy, Send, Sized, Sync};
+use crate::intrinsics::assume;
+use crate::marker::{self, Copy};
use crate::mem;
-use crate::ops::{self, Bound, FnMut, Range, RangeBounds};
+use crate::ops::{FnMut, Range, RangeBounds};
use crate::option::Option;
use crate::option::Option::{None, Some};
use crate::ptr::{self, NonNull};
/// Pure rust memchr implementation, taken from rust-memchr
pub mod memchr;
+mod ascii;
+mod cmp;
+mod index;
+mod iter;
+mod raw;
mod rotate;
mod sort;
-//
-// Extension traits
-//
+use iter::GenericSplitN;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use iter::{Chunks, ChunksMut, Windows};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use iter::{Iter, IterMut};
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use iter::{RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut};
+
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+pub use iter::{RSplit, RSplitMut};
+
+#[stable(feature = "chunks_exact", since = "1.31.0")]
+pub use iter::{ChunksExact, ChunksExactMut};
+
+#[stable(feature = "rchunks", since = "1.31.0")]
+pub use iter::{RChunks, RChunksExact, RChunksExactMut, RChunksMut};
+
+#[unstable(feature = "array_chunks", issue = "74985")]
+pub use iter::{ArrayChunks, ArrayChunksMut};
+
+#[unstable(feature = "array_windows", issue = "75027")]
+pub use iter::ArrayWindows;
+
+#[unstable(feature = "split_inclusive", issue = "72360")]
+pub use iter::{SplitInclusive, SplitInclusiveMut};
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use raw::{from_raw_parts, from_raw_parts_mut};
+
+#[stable(feature = "from_ref", since = "1.28.0")]
+pub use raw::{from_mut, from_ref};
+
+// This function is public only because there is no other way to unit test heapsort.
+#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")]
+pub use sort::heapsort;
+
+#[stable(feature = "slice_get_slice", since = "1.28.0")]
+pub use index::SliceIndex;
+
+#[unstable(feature = "slice_check_range", issue = "76393")]
+pub use index::check_range;
#[lang = "slice"]
#[cfg(not(test))]
unsafe { &mut *index.get_unchecked_mut(self) }
}
- /// Converts a range over this slice to [`Range`].
- ///
- /// The returned range is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`].
- ///
- /// [`get_unchecked`]: #method.get_unchecked
- /// [`get_unchecked_mut`]: #method.get_unchecked_mut
- ///
- /// # Panics
- ///
- /// Panics if the range is out of bounds.
- ///
- /// # Examples
- ///
- /// ```
- /// #![feature(slice_check_range)]
- ///
- /// let v = [10, 40, 30];
- /// assert_eq!(1..2, v.check_range(1..2));
- /// assert_eq!(0..2, v.check_range(..2));
- /// assert_eq!(1..3, v.check_range(1..));
- /// ```
- ///
- /// Panics when [`Index::index`] would panic:
- ///
- /// ```should_panic
- /// #![feature(slice_check_range)]
- ///
- /// [10, 40, 30].check_range(2..1);
- /// ```
- ///
- /// ```should_panic
- /// #![feature(slice_check_range)]
- ///
- /// [10, 40, 30].check_range(1..4);
- /// ```
- ///
- /// ```should_panic
- /// #![feature(slice_check_range)]
- ///
- /// [10, 40, 30].check_range(1..=usize::MAX);
- /// ```
- ///
- /// [`Index::index`]: ops::Index::index
- #[track_caller]
- #[unstable(feature = "slice_check_range", issue = "76393")]
- pub fn check_range<R: RangeBounds<usize>>(&self, range: R) -> Range<usize> {
- let start = match range.start_bound() {
- Bound::Included(&start) => start,
- Bound::Excluded(start) => {
- start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
- }
- Bound::Unbounded => 0,
- };
-
- let len = self.len();
- let end = match range.end_bound() {
- Bound::Included(end) => {
- end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
- }
- Bound::Excluded(&end) => end,
- Bound::Unbounded => len,
- };
-
- if start > end {
- slice_index_order_fail(start, end);
- }
- if end > len {
- slice_end_index_len_fail(end, len);
- }
-
- Range { start, end }
- }
-
/// Returns a raw pointer to the slice's buffer.
///
/// The caller must ensure that the slice outlives the pointer this
}
}
+ /// Returns an iterator over overlapping windows of `N` elements of a slice,
+ /// starting at the beginning of the slice.
+ ///
+ /// This is the const generic equivalent of [`windows`].
+ ///
+ /// If `N` is smaller than the size of the array, it will return no windows.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N` is 0. This check will most probably get changed to a compile time
+ /// error before this method gets stabilized.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(array_windows)]
+ /// let slice = [0, 1, 2, 3];
+ /// let mut iter = slice.array_windows();
+ /// assert_eq!(iter.next().unwrap(), &[0, 1]);
+ /// assert_eq!(iter.next().unwrap(), &[1, 2]);
+ /// assert_eq!(iter.next().unwrap(), &[2, 3]);
+ /// assert!(iter.next().is_none());
+ /// ```
+ ///
+ /// [`windows`]: #method.windows
+ #[unstable(feature = "array_windows", issue = "75027")]
+ #[inline]
+ pub fn array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N> {
+ assert_ne!(N, 0);
+
+ let num_windows = self.len().saturating_sub(N - 1);
+ ArrayWindows { slice_head: self.as_ptr(), num: num_windows, marker: marker::PhantomData }
+ }
+
/// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end
/// of the slice.
///
where
T: PartialEq,
{
- x.slice_contains(self)
+ cmp::SliceContains::slice_contains(x, self)
}
/// Returns `true` if `needle` is a prefix of the slice.
where
T: Copy,
{
- let Range { start: src_start, end: src_end } = self.check_range(src);
+ let Range { start: src_start, end: src_end } = check_range(self.len(), src);
let count = src_end - src_start;
assert!(dest <= self.len() - count, "dest is out of bounds");
// SAFETY: the conditions for `ptr::copy` have all been checked above,
}
}
-#[lang = "slice_u8"]
-#[cfg(not(test))]
-impl [u8] {
- /// Checks if all bytes in this slice are within the ASCII range.
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn is_ascii(&self) -> bool {
- is_ascii(self)
- }
-
- /// Checks that two slices are an ASCII case-insensitive match.
- ///
- /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
- /// but without allocating and copying temporaries.
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
- self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.eq_ignore_ascii_case(b))
- }
-
- /// Converts this slice to its ASCII upper case equivalent in-place.
- ///
- /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
- /// but non-ASCII letters are unchanged.
- ///
- /// To return a new uppercased value without modifying the existing one, use
- /// [`to_ascii_uppercase`].
- ///
- /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn make_ascii_uppercase(&mut self) {
- for byte in self {
- byte.make_ascii_uppercase();
- }
- }
-
- /// Converts this slice to its ASCII lower case equivalent in-place.
- ///
- /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
- /// but non-ASCII letters are unchanged.
- ///
- /// To return a new lowercased value without modifying the existing one, use
- /// [`to_ascii_lowercase`].
- ///
- /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
- #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
- #[inline]
- pub fn make_ascii_lowercase(&mut self) {
- for byte in self {
- byte.make_ascii_lowercase();
- }
- }
-}
-
-/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed
-/// from `../str/mod.rs`, which does something similar for utf8 validation.
-#[inline]
-fn contains_nonascii(v: usize) -> bool {
- const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize;
- (NONASCII_MASK & v) != 0
-}
-
-/// Optimized ASCII test that will use usize-at-a-time operations instead of
-/// byte-at-a-time operations (when possible).
-///
-/// The algorithm we use here is pretty simple. If `s` is too short, we just
-/// check each byte and be done with it. Otherwise:
-///
-/// - Read the first word with an unaligned load.
-/// - Align the pointer, read subsequent words until end with aligned loads.
-/// - Read the last `usize` from `s` with an unaligned load.
-///
-/// If any of these loads produces something for which `contains_nonascii`
-/// (above) returns true, then we know the answer is false.
-#[inline]
-fn is_ascii(s: &[u8]) -> bool {
- const USIZE_SIZE: usize = mem::size_of::<usize>();
-
- let len = s.len();
- let align_offset = s.as_ptr().align_offset(USIZE_SIZE);
-
- // If we wouldn't gain anything from the word-at-a-time implementation, fall
- // back to a scalar loop.
- //
- // We also do this for architectures where `size_of::<usize>()` isn't
- // sufficient alignment for `usize`, because it's a weird edge case.
- if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::<usize>() {
- return s.iter().all(|b| b.is_ascii());
- }
-
- // We always read the first word unaligned, which means `align_offset` is
- // 0, we'd read the same value again for the aligned read.
- let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset };
-
- let start = s.as_ptr();
- // SAFETY: We verify `len < USIZE_SIZE` above.
- let first_word = unsafe { (start as *const usize).read_unaligned() };
-
- if contains_nonascii(first_word) {
- return false;
- }
- // We checked this above, somewhat implicitly. Note that `offset_to_aligned`
- // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked
- // above.
- debug_assert!(offset_to_aligned <= len);
-
- // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the
- // middle chunk of the slice.
- let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize };
-
- // `byte_pos` is the byte index of `word_ptr`, used for loop end checks.
- let mut byte_pos = offset_to_aligned;
-
- // Paranoia check about alignment, since we're about to do a bunch of
- // unaligned loads. In practice this should be impossible barring a bug in
- // `align_offset` though.
- debug_assert_eq!((word_ptr as usize) % mem::align_of::<usize>(), 0);
-
- // Read subsequent words until the last aligned word, excluding the last
- // aligned word by itself to be done in tail check later, to ensure that
- // tail is always one `usize` at most to extra branch `byte_pos == len`.
- while byte_pos < len - USIZE_SIZE {
- debug_assert!(
- // Sanity check that the read is in bounds
- (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) &&
- // And that our assumptions about `byte_pos` hold.
- (word_ptr as usize) - (start as usize) == byte_pos
- );
-
- // SAFETY: We know `word_ptr` is properly aligned (because of
- // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end
- let word = unsafe { word_ptr.read() };
- if contains_nonascii(word) {
- return false;
- }
-
- byte_pos += USIZE_SIZE;
- // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that
- // after this `add`, `word_ptr` will be at most one-past-the-end.
- word_ptr = unsafe { word_ptr.add(1) };
- }
-
- // Sanity check to ensure there really is only one `usize` left. This should
- // be guaranteed by our loop condition.
- debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE);
-
- // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start.
- let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() };
-
- !contains_nonascii(last_word)
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::Index<I> for [T]
-where
- I: SliceIndex<[T]>,
-{
- type Output = I::Output;
-
- #[inline]
- fn index(&self, index: I) -> &I::Output {
- index.index(self)
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, I> ops::IndexMut<I> for [T]
-where
- I: SliceIndex<[T]>,
-{
- #[inline]
- fn index_mut(&mut self, index: I) -> &mut I::Output {
- index.index_mut(self)
- }
-}
-
-#[inline(never)]
-#[cold]
-#[track_caller]
-fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
- panic!("range start index {} out of range for slice of length {}", index, len);
-}
-
-#[inline(never)]
-#[cold]
-#[track_caller]
-fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
- panic!("range end index {} out of range for slice of length {}", index, len);
-}
-
-#[inline(never)]
-#[cold]
-#[track_caller]
-fn slice_index_order_fail(index: usize, end: usize) -> ! {
- panic!("slice index starts at {} but ends at {}", index, end);
-}
-
-#[inline(never)]
-#[cold]
-#[track_caller]
-fn slice_start_index_overflow_fail() -> ! {
- panic!("attempted to index slice from after maximum usize");
-}
-
-#[inline(never)]
-#[cold]
-#[track_caller]
-fn slice_end_index_overflow_fail() -> ! {
- panic!("attempted to index slice up to maximum usize");
-}
-
-mod private_slice_index {
- use super::ops;
- #[stable(feature = "slice_get_slice", since = "1.28.0")]
- pub trait Sealed {}
-
- #[stable(feature = "slice_get_slice", since = "1.28.0")]
- impl Sealed for usize {}
- #[stable(feature = "slice_get_slice", since = "1.28.0")]
- impl Sealed for ops::Range<usize> {}
- #[stable(feature = "slice_get_slice", since = "1.28.0")]
- impl Sealed for ops::RangeTo<usize> {}
- #[stable(feature = "slice_get_slice", since = "1.28.0")]
- impl Sealed for ops::RangeFrom<usize> {}
- #[stable(feature = "slice_get_slice", since = "1.28.0")]
- impl Sealed for ops::RangeFull {}
- #[stable(feature = "slice_get_slice", since = "1.28.0")]
- impl Sealed for ops::RangeInclusive<usize> {}
- #[stable(feature = "slice_get_slice", since = "1.28.0")]
- impl Sealed for ops::RangeToInclusive<usize> {}
-}
-
-/// A helper trait used for indexing operations.
-///
-/// Implementations of this trait have to promise that if the argument
-/// to `get_(mut_)unchecked` is a safe reference, then so is the result.
-#[stable(feature = "slice_get_slice", since = "1.28.0")]
-#[rustc_on_unimplemented(
- on(T = "str", label = "string indices are ranges of `usize`",),
- on(
- all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"),
- note = "you can use `.chars().nth()` or `.bytes().nth()`\n\
- for more information, see chapter 8 in The Book: \
- <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>"
- ),
- message = "the type `{T}` cannot be indexed by `{Self}`",
- label = "slice indices are of type `usize` or ranges of `usize`"
-)]
-pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed {
- /// The output type returned by methods.
- #[stable(feature = "slice_get_slice", since = "1.28.0")]
- type Output: ?Sized;
-
- /// Returns a shared reference to the output at this location, if in
- /// bounds.
- #[unstable(feature = "slice_index_methods", issue = "none")]
- fn get(self, slice: &T) -> Option<&Self::Output>;
-
- /// Returns a mutable reference to the output at this location, if in
- /// bounds.
- #[unstable(feature = "slice_index_methods", issue = "none")]
- fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>;
-
- /// Returns a shared reference to the output at this location, without
- /// performing any bounds checking.
- /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
- /// is *[undefined behavior]* even if the resulting reference is not used.
- ///
- /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
- #[unstable(feature = "slice_index_methods", issue = "none")]
- unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;
-
- /// Returns a mutable reference to the output at this location, without
- /// performing any bounds checking.
- /// Calling this method with an out-of-bounds index or a dangling `slice` pointer
- /// is *[undefined behavior]* even if the resulting reference is not used.
- ///
- /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
- #[unstable(feature = "slice_index_methods", issue = "none")]
- unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output;
-
- /// Returns a shared reference to the output at this location, panicking
- /// if out of bounds.
- #[unstable(feature = "slice_index_methods", issue = "none")]
- #[track_caller]
- fn index(self, slice: &T) -> &Self::Output;
-
- /// Returns a mutable reference to the output at this location, panicking
- /// if out of bounds.
- #[unstable(feature = "slice_index_methods", issue = "none")]
- #[track_caller]
- fn index_mut(self, slice: &mut T) -> &mut Self::Output;
-}
-
-#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for usize {
- type Output = T;
-
- #[inline]
- fn get(self, slice: &[T]) -> Option<&T> {
- // SAFETY: `self` is checked to be in bounds.
- if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None }
- }
-
- #[inline]
- fn get_mut(self, slice: &mut [T]) -> Option<&mut T> {
- // SAFETY: `self` is checked to be in bounds.
- if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None }
- }
-
- #[inline]
- unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
- // SAFETY: the caller guarantees that `slice` is not dangling, so it
- // cannot be longer than `isize::MAX`. They also guarantee that
- // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
- // so the call to `add` is safe.
- unsafe { slice.as_ptr().add(self) }
- }
-
- #[inline]
- unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T {
- // SAFETY: see comments for `get_unchecked` above.
- unsafe { slice.as_mut_ptr().add(self) }
- }
-
- #[inline]
- fn index(self, slice: &[T]) -> &T {
- // N.B., use intrinsic indexing
- &(*slice)[self]
- }
-
- #[inline]
- fn index_mut(self, slice: &mut [T]) -> &mut T {
- // N.B., use intrinsic indexing
- &mut (*slice)[self]
- }
-}
-
-#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> {
- type Output = [T];
-
- #[inline]
- fn get(self, slice: &[T]) -> Option<&[T]> {
- if self.start > self.end || self.end > slice.len() {
- None
- } else {
- // SAFETY: `self` is checked to be valid and in bounds above.
- unsafe { Some(&*self.get_unchecked(slice)) }
- }
- }
-
- #[inline]
- fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
- if self.start > self.end || self.end > slice.len() {
- None
- } else {
- // SAFETY: `self` is checked to be valid and in bounds above.
- unsafe { Some(&mut *self.get_unchecked_mut(slice)) }
- }
- }
-
- #[inline]
- unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
- // SAFETY: the caller guarantees that `slice` is not dangling, so it
- // cannot be longer than `isize::MAX`. They also guarantee that
- // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
- // so the call to `add` is safe.
- unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) }
- }
-
- #[inline]
- unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
- // SAFETY: see comments for `get_unchecked` above.
- unsafe {
- ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
- }
- }
-
- #[inline]
- fn index(self, slice: &[T]) -> &[T] {
- if self.start > self.end {
- slice_index_order_fail(self.start, self.end);
- } else if self.end > slice.len() {
- slice_end_index_len_fail(self.end, slice.len());
- }
- // SAFETY: `self` is checked to be valid and in bounds above.
- unsafe { &*self.get_unchecked(slice) }
- }
-
- #[inline]
- fn index_mut(self, slice: &mut [T]) -> &mut [T] {
- if self.start > self.end {
- slice_index_order_fail(self.start, self.end);
- } else if self.end > slice.len() {
- slice_end_index_len_fail(self.end, slice.len());
- }
- // SAFETY: `self` is checked to be valid and in bounds above.
- unsafe { &mut *self.get_unchecked_mut(slice) }
- }
-}
-
-#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> {
- type Output = [T];
-
- #[inline]
- fn get(self, slice: &[T]) -> Option<&[T]> {
- (0..self.end).get(slice)
- }
-
- #[inline]
- fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
- (0..self.end).get_mut(slice)
- }
-
- #[inline]
- unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
- // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
- unsafe { (0..self.end).get_unchecked(slice) }
- }
-
- #[inline]
- unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
- // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
- unsafe { (0..self.end).get_unchecked_mut(slice) }
- }
-
- #[inline]
- fn index(self, slice: &[T]) -> &[T] {
- (0..self.end).index(slice)
- }
-
- #[inline]
- fn index_mut(self, slice: &mut [T]) -> &mut [T] {
- (0..self.end).index_mut(slice)
- }
-}
-
-#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> {
- type Output = [T];
-
- #[inline]
- fn get(self, slice: &[T]) -> Option<&[T]> {
- (self.start..slice.len()).get(slice)
- }
-
- #[inline]
- fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
- (self.start..slice.len()).get_mut(slice)
- }
-
- #[inline]
- unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
- // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
- unsafe { (self.start..slice.len()).get_unchecked(slice) }
- }
-
- #[inline]
- unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
- // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
- unsafe { (self.start..slice.len()).get_unchecked_mut(slice) }
- }
-
- #[inline]
- fn index(self, slice: &[T]) -> &[T] {
- if self.start > slice.len() {
- slice_start_index_len_fail(self.start, slice.len());
- }
- // SAFETY: `self` is checked to be valid and in bounds above.
- unsafe { &*self.get_unchecked(slice) }
- }
-
- #[inline]
- fn index_mut(self, slice: &mut [T]) -> &mut [T] {
- if self.start > slice.len() {
- slice_start_index_len_fail(self.start, slice.len());
- }
- // SAFETY: `self` is checked to be valid and in bounds above.
- unsafe { &mut *self.get_unchecked_mut(slice) }
- }
-}
-
-#[stable(feature = "slice_get_slice_impls", since = "1.15.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeFull {
- type Output = [T];
-
- #[inline]
- fn get(self, slice: &[T]) -> Option<&[T]> {
- Some(slice)
- }
-
- #[inline]
- fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
- Some(slice)
- }
-
- #[inline]
- unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
- slice
- }
-
- #[inline]
- unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
- slice
- }
-
- #[inline]
- fn index(self, slice: &[T]) -> &[T] {
- slice
- }
-
- #[inline]
- fn index_mut(self, slice: &mut [T]) -> &mut [T] {
- slice
- }
-}
-
-#[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
- type Output = [T];
-
- #[inline]
- fn get(self, slice: &[T]) -> Option<&[T]> {
- if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) }
- }
-
- #[inline]
- fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
- if *self.end() == usize::MAX {
- None
- } else {
- (*self.start()..self.end() + 1).get_mut(slice)
- }
- }
-
- #[inline]
- unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
- // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
- unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) }
- }
-
- #[inline]
- unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
- // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
- unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) }
- }
-
- #[inline]
- fn index(self, slice: &[T]) -> &[T] {
- if *self.end() == usize::MAX {
- slice_end_index_overflow_fail();
- }
- (*self.start()..self.end() + 1).index(slice)
- }
-
- #[inline]
- fn index_mut(self, slice: &mut [T]) -> &mut [T] {
- if *self.end() == usize::MAX {
- slice_end_index_overflow_fail();
- }
- (*self.start()..self.end() + 1).index_mut(slice)
- }
-}
-
-#[stable(feature = "inclusive_range", since = "1.26.0")]
-unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> {
- type Output = [T];
-
- #[inline]
- fn get(self, slice: &[T]) -> Option<&[T]> {
- (0..=self.end).get(slice)
- }
-
- #[inline]
- fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> {
- (0..=self.end).get_mut(slice)
- }
-
- #[inline]
- unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
- // SAFETY: the caller has to uphold the safety contract for `get_unchecked`.
- unsafe { (0..=self.end).get_unchecked(slice) }
- }
-
- #[inline]
- unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] {
- // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`.
- unsafe { (0..=self.end).get_unchecked_mut(slice) }
- }
-
- #[inline]
- fn index(self, slice: &[T]) -> &[T] {
- (0..=self.end).index(slice)
- }
-
- #[inline]
- fn index_mut(self, slice: &mut [T]) -> &mut [T] {
- (0..=self.end).index_mut(slice)
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Common traits
-////////////////////////////////////////////////////////////////////////////////
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Default for &[T] {
- /// Creates an empty slice.
- fn default() -> Self {
- &[]
+impl<T> Default for &[T] {
+ /// Creates an empty slice.
+ fn default() -> Self {
+ &[]
}
}
&mut []
}
}
-
-//
-// Iterators
-//
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a [T] {
- type Item = &'a T;
- type IntoIter = Iter<'a, T>;
-
- fn into_iter(self) -> Iter<'a, T> {
- self.iter()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a mut [T] {
- type Item = &'a mut T;
- type IntoIter = IterMut<'a, T>;
-
- fn into_iter(self) -> IterMut<'a, T> {
- self.iter_mut()
- }
-}
-
-// Macro helper functions
-#[inline(always)]
-fn size_from_ptr<T>(_: *const T) -> usize {
- mem::size_of::<T>()
-}
-
-// Inlining is_empty and len makes a huge performance difference
-macro_rules! is_empty {
- // The way we encode the length of a ZST iterator, this works both for ZST
- // and non-ZST.
- ($self: ident) => {
- $self.ptr.as_ptr() as *const T == $self.end
- };
-}
-
-// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
-// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
-macro_rules! len {
- ($self: ident) => {{
- #![allow(unused_unsafe)] // we're sometimes used within an unsafe block
-
- let start = $self.ptr;
- let size = size_from_ptr(start.as_ptr());
- if size == 0 {
- // This _cannot_ use `unchecked_sub` because we depend on wrapping
- // to represent the length of long ZST slice iterators.
- ($self.end as usize).wrapping_sub(start.as_ptr() as usize)
- } else {
- // We know that `start <= end`, so can do better than `offset_from`,
- // which needs to deal in signed. By setting appropriate flags here
- // we can tell LLVM this, which helps it remove bounds checks.
- // SAFETY: By the type invariant, `start <= end`
- let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) };
- // By also telling LLVM that the pointers are apart by an exact
- // multiple of the type size, it can optimize `len() == 0` down to
- // `start == end` instead of `(end - start) < size`.
- // SAFETY: By the type invariant, the pointers are aligned so the
- // distance between them must be a multiple of pointee size
- unsafe { exact_div(diff, size) }
- }
- }};
-}
-
-// The shared definition of the `Iter` and `IterMut` iterators
-macro_rules! iterator {
- (
- struct $name:ident -> $ptr:ty,
- $elem:ty,
- $raw_mut:tt,
- {$( $mut_:tt )?},
- {$($extra:tt)*}
- ) => {
- // Returns the first element and moves the start of the iterator forwards by 1.
- // Greatly improves performance compared to an inlined function. The iterator
- // must not be empty.
- macro_rules! next_unchecked {
- ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)}
- }
-
- // Returns the last element and moves the end of the iterator backwards by 1.
- // Greatly improves performance compared to an inlined function. The iterator
- // must not be empty.
- macro_rules! next_back_unchecked {
- ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)}
- }
-
- // Shrinks the iterator when T is a ZST, by moving the end of the iterator
- // backwards by `n`. `n` must not exceed `self.len()`.
- macro_rules! zst_shrink {
- ($self: ident, $n: ident) => {
- $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T;
- }
- }
-
- impl<'a, T> $name<'a, T> {
- // Helper function for creating a slice from the iterator.
- #[inline(always)]
- fn make_slice(&self) -> &'a [T] {
- // SAFETY: the iterator was created from a slice with pointer
- // `self.ptr` and length `len!(self)`. This guarantees that all
- // the prerequisites for `from_raw_parts` are fulfilled.
- unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) }
- }
-
- // Helper function for moving the start of the iterator forwards by `offset` elements,
- // returning the old start.
- // Unsafe because the offset must not exceed `self.len()`.
- #[inline(always)]
- unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T {
- if mem::size_of::<T>() == 0 {
- zst_shrink!(self, offset);
- self.ptr.as_ptr()
- } else {
- let old = self.ptr.as_ptr();
- // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
- // so this new pointer is inside `self` and thus guaranteed to be non-null.
- self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) };
- old
- }
- }
-
- // Helper function for moving the end of the iterator backwards by `offset` elements,
- // returning the new end.
- // Unsafe because the offset must not exceed `self.len()`.
- #[inline(always)]
- unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T {
- if mem::size_of::<T>() == 0 {
- zst_shrink!(self, offset);
- self.ptr.as_ptr()
- } else {
- // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`,
- // which is guaranteed to not overflow an `isize`. Also, the resulting pointer
- // is in bounds of `slice`, which fulfills the other requirements for `offset`.
- self.end = unsafe { self.end.offset(-offset) };
- self.end
- }
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<T> ExactSizeIterator for $name<'_, T> {
- #[inline(always)]
- fn len(&self) -> usize {
- len!(self)
- }
-
- #[inline(always)]
- fn is_empty(&self) -> bool {
- is_empty!(self)
- }
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, T> Iterator for $name<'a, T> {
- type Item = $elem;
-
- #[inline]
- fn next(&mut self) -> Option<$elem> {
- // could be implemented with slices, but this avoids bounds checks
-
- // SAFETY: `assume` calls are safe since a slice's start pointer
- // must be non-null, and slices over non-ZSTs must also have a
- // non-null end pointer. The call to `next_unchecked!` is safe
- // since we check if the iterator is empty first.
- unsafe {
- assume(!self.ptr.as_ptr().is_null());
- if mem::size_of::<T>() != 0 {
- assume(!self.end.is_null());
- }
- if is_empty!(self) {
- None
- } else {
- Some(next_unchecked!(self))
- }
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let exact = len!(self);
- (exact, Some(exact))
- }
-
- #[inline]
- fn count(self) -> usize {
- len!(self)
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<$elem> {
- if n >= len!(self) {
- // This iterator is now empty.
- if mem::size_of::<T>() == 0 {
- // We have to do it this way as `ptr` may never be 0, but `end`
- // could be (due to wrapping).
- self.end = self.ptr.as_ptr();
- } else {
- // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr
- unsafe {
- self.ptr = NonNull::new_unchecked(self.end as *mut T);
- }
- }
- return None;
- }
- // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs.
- unsafe {
- self.post_inc_start(n as isize);
- Some(next_unchecked!(self))
- }
- }
-
- #[inline]
- fn last(mut self) -> Option<$elem> {
- self.next_back()
- }
-
- // We override the default implementation, which uses `try_fold`,
- // because this simple implementation generates less LLVM IR and is
- // faster to compile.
- #[inline]
- fn for_each<F>(mut self, mut f: F)
- where
- Self: Sized,
- F: FnMut(Self::Item),
- {
- while let Some(x) = self.next() {
- f(x);
- }
- }
-
- // We override the default implementation, which uses `try_fold`,
- // because this simple implementation generates less LLVM IR and is
- // faster to compile.
- #[inline]
- fn all<F>(&mut self, mut f: F) -> bool
- where
- Self: Sized,
- F: FnMut(Self::Item) -> bool,
- {
- while let Some(x) = self.next() {
- if !f(x) {
- return false;
- }
- }
- true
- }
-
- // We override the default implementation, which uses `try_fold`,
- // because this simple implementation generates less LLVM IR and is
- // faster to compile.
- #[inline]
- fn any<F>(&mut self, mut f: F) -> bool
- where
- Self: Sized,
- F: FnMut(Self::Item) -> bool,
- {
- while let Some(x) = self.next() {
- if f(x) {
- return true;
- }
- }
- false
- }
-
- // We override the default implementation, which uses `try_fold`,
- // because this simple implementation generates less LLVM IR and is
- // faster to compile.
- #[inline]
- fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
- where
- Self: Sized,
- P: FnMut(&Self::Item) -> bool,
- {
- while let Some(x) = self.next() {
- if predicate(&x) {
- return Some(x);
- }
- }
- None
- }
-
- // We override the default implementation, which uses `try_fold`,
- // because this simple implementation generates less LLVM IR and is
- // faster to compile.
- #[inline]
- fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
- where
- Self: Sized,
- F: FnMut(Self::Item) -> Option<B>,
- {
- while let Some(x) = self.next() {
- if let Some(y) = f(x) {
- return Some(y);
- }
- }
- None
- }
-
- // We override the default implementation, which uses `try_fold`,
- // because this simple implementation generates less LLVM IR and is
- // faster to compile. Also, the `assume` avoids a bounds check.
- #[inline]
- #[rustc_inherit_overflow_checks]
- fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
- Self: Sized,
- P: FnMut(Self::Item) -> bool,
- {
- let n = len!(self);
- let mut i = 0;
- while let Some(x) = self.next() {
- if predicate(x) {
- // SAFETY: we are guaranteed to be in bounds by the loop invariant:
- // when `i >= n`, `self.next()` returns `None` and the loop breaks.
- unsafe { assume(i < n) };
- return Some(i);
- }
- i += 1;
- }
- None
- }
-
- // We override the default implementation, which uses `try_fold`,
- // because this simple implementation generates less LLVM IR and is
- // faster to compile. Also, the `assume` avoids a bounds check.
- #[inline]
- fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
- P: FnMut(Self::Item) -> bool,
- Self: Sized + ExactSizeIterator + DoubleEndedIterator
- {
- let n = len!(self);
- let mut i = n;
- while let Some(x) = self.next_back() {
- i -= 1;
- if predicate(x) {
- // SAFETY: `i` must be lower than `n` since it starts at `n`
- // and is only decreasing.
- unsafe { assume(i < n) };
- return Some(i);
- }
- }
- None
- }
-
- #[doc(hidden)]
- unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
- // SAFETY: the caller must guarantee that `i` is in bounds of
- // the underlying slice, so `i` cannot overflow an `isize`, and
- // the returned references is guaranteed to refer to an element
- // of the slice and thus guaranteed to be valid.
- //
- // Also note that the caller also guarantees that we're never
- // called with the same index again, and that no other methods
- // that will access this subslice are called, so it is valid
- // for the returned reference to be mutable in the case of
- // `IterMut`
- unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) }
- }
-
- $($extra)*
- }
-
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, T> DoubleEndedIterator for $name<'a, T> {
- #[inline]
- fn next_back(&mut self) -> Option<$elem> {
- // could be implemented with slices, but this avoids bounds checks
-
- // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null,
- // and slices over non-ZSTs must also have a non-null end pointer.
- // The call to `next_back_unchecked!` is safe since we check if the iterator is
- // empty first.
- unsafe {
- assume(!self.ptr.as_ptr().is_null());
- if mem::size_of::<T>() != 0 {
- assume(!self.end.is_null());
- }
- if is_empty!(self) {
- None
- } else {
- Some(next_back_unchecked!(self))
- }
- }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<$elem> {
- if n >= len!(self) {
- // This iterator is now empty.
- self.end = self.ptr.as_ptr();
- return None;
- }
- // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs.
- unsafe {
- self.pre_dec_end(n as isize);
- Some(next_back_unchecked!(self))
- }
- }
- }
-
- #[stable(feature = "fused", since = "1.26.0")]
- impl<T> FusedIterator for $name<'_, T> {}
-
- #[unstable(feature = "trusted_len", issue = "37572")]
- unsafe impl<T> TrustedLen for $name<'_, T> {}
- }
-}
-
-/// Immutable slice iterator
-///
-/// This struct is created by the [`iter`] method on [slices].
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// // First, we declare a type which has `iter` method to get the `Iter` struct (&[usize here]):
-/// let slice = &[1, 2, 3];
-///
-/// // Then, we iterate over it:
-/// for element in slice.iter() {
-/// println!("{}", element);
-/// }
-/// ```
-///
-/// [`iter`]: ../../std/primitive.slice.html#method.iter
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Iter<'a, T: 'a> {
- ptr: NonNull<T>,
- end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
- // ptr == end is a quick test for the Iterator being empty, that works
- // for both ZST and non-ZST.
- _marker: marker::PhantomData<&'a T>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("Iter").field(&self.as_slice()).finish()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync> Sync for Iter<'_, T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync> Send for Iter<'_, T> {}
-
-impl<'a, T> Iter<'a, T> {
- /// Views the underlying data as a subslice of the original data.
- ///
- /// This has the same lifetime as the original slice, and so the
- /// iterator can continue to be used while this exists.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// // First, we declare a type which has the `iter` method to get the `Iter`
- /// // struct (&[usize here]):
- /// let slice = &[1, 2, 3];
- ///
- /// // Then, we get the iterator:
- /// let mut iter = slice.iter();
- /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]":
- /// println!("{:?}", iter.as_slice());
- ///
- /// // Next, we move to the second element of the slice:
- /// iter.next();
- /// // Now `as_slice` returns "[2, 3]":
- /// println!("{:?}", iter.as_slice());
- /// ```
- #[stable(feature = "iter_to_slice", since = "1.4.0")]
- pub fn as_slice(&self) -> &'a [T] {
- self.make_slice()
- }
-}
-
-iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, {
- fn is_sorted_by<F>(self, mut compare: F) -> bool
- where
- Self: Sized,
- F: FnMut(&Self::Item, &Self::Item) -> Option<Ordering>,
- {
- self.as_slice().windows(2).all(|w| {
- compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false)
- })
- }
-}}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for Iter<'_, T> {
- fn clone(&self) -> Self {
- Iter { ptr: self.ptr, end: self.end, _marker: self._marker }
- }
-}
-
-#[stable(feature = "slice_iter_as_ref", since = "1.13.0")]
-impl<T> AsRef<[T]> for Iter<'_, T> {
- fn as_ref(&self) -> &[T] {
- self.as_slice()
- }
-}
-
-/// Mutable slice iterator.
-///
-/// This struct is created by the [`iter_mut`] method on [slices].
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// // First, we declare a type which has `iter_mut` method to get the `IterMut`
-/// // struct (&[usize here]):
-/// let mut slice = &mut [1, 2, 3];
-///
-/// // Then, we iterate over it and increment each element value:
-/// for element in slice.iter_mut() {
-/// *element += 1;
-/// }
-///
-/// // We now have "[2, 3, 4]":
-/// println!("{:?}", slice);
-/// ```
-///
-/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct IterMut<'a, T: 'a> {
- ptr: NonNull<T>,
- end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that
- // ptr == end is a quick test for the Iterator being empty, that works
- // for both ZST and non-ZST.
- _marker: marker::PhantomData<&'a mut T>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("IterMut").field(&self.make_slice()).finish()
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync> Sync for IterMut<'_, T> {}
-#[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Send> Send for IterMut<'_, T> {}
-
-impl<'a, T> IterMut<'a, T> {
- /// Views the underlying data as a subslice of the original data.
- ///
- /// To avoid creating `&mut` references that alias, this is forced
- /// to consume the iterator.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// // First, we declare a type which has `iter_mut` method to get the `IterMut`
- /// // struct (&[usize here]):
- /// let mut slice = &mut [1, 2, 3];
- ///
- /// {
- /// // Then, we get the iterator:
- /// let mut iter = slice.iter_mut();
- /// // We move to next element:
- /// iter.next();
- /// // So if we print what `into_slice` method returns here, we have "[2, 3]":
- /// println!("{:?}", iter.into_slice());
- /// }
- ///
- /// // Now let's modify a value of the slice:
- /// {
- /// // First we get back the iterator:
- /// let mut iter = slice.iter_mut();
- /// // We change the value of the first element of the slice returned by the `next` method:
- /// *iter.next().unwrap() += 1;
- /// }
- /// // Now slice is "[2, 2, 3]":
- /// println!("{:?}", slice);
- /// ```
- #[stable(feature = "iter_to_slice", since = "1.4.0")]
- pub fn into_slice(self) -> &'a mut [T] {
- // SAFETY: the iterator was created from a mutable slice with pointer
- // `self.ptr` and length `len!(self)`. This guarantees that all the prerequisites
- // for `from_raw_parts_mut` are fulfilled.
- unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) }
- }
-
- /// Views the underlying data as a subslice of the original data.
- ///
- /// To avoid creating `&mut [T]` references that alias, the returned slice
- /// borrows its lifetime from the iterator the method is applied on.
- ///
- /// # Examples
- ///
- /// Basic usage:
- ///
- /// ```
- /// # #![feature(slice_iter_mut_as_slice)]
- /// let mut slice: &mut [usize] = &mut [1, 2, 3];
- ///
- /// // First, we get the iterator:
- /// let mut iter = slice.iter_mut();
- /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]":
- /// assert_eq!(iter.as_slice(), &[1, 2, 3]);
- ///
- /// // Next, we move to the second element of the slice:
- /// iter.next();
- /// // Now `as_slice` returns "[2, 3]":
- /// assert_eq!(iter.as_slice(), &[2, 3]);
- /// ```
- #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")]
- pub fn as_slice(&self) -> &[T] {
- self.make_slice()
- }
-}
-
-iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}}
-
-/// An internal abstraction over the splitting iterators, so that
-/// splitn, splitn_mut etc can be implemented once.
-#[doc(hidden)]
-trait SplitIter: DoubleEndedIterator {
- /// Marks the underlying iterator as complete, extracting the remaining
- /// portion of the slice.
- fn finish(&mut self) -> Option<Self::Item>;
-}
-
-/// An iterator over subslices separated by elements that match a predicate
-/// function.
-///
-/// This struct is created by the [`split`] method on [slices].
-///
-/// [`split`]: ../../std/primitive.slice.html#method.split
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Split<'a, T: 'a, P>
-where
- P: FnMut(&T) -> bool,
-{
- v: &'a [T],
- pred: P,
- finished: bool,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for Split<'_, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish()
- }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T, P> Clone for Split<'_, T, P>
-where
- P: Clone + FnMut(&T) -> bool,
-{
- fn clone(&self) -> Self {
- Split { v: self.v, pred: self.pred.clone(), finished: self.finished }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, P> Iterator for Split<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- type Item = &'a [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a [T]> {
- if self.finished {
- return None;
- }
-
- match self.v.iter().position(|x| (self.pred)(x)) {
- None => self.finish(),
- Some(idx) => {
- let ret = Some(&self.v[..idx]);
- self.v = &self.v[idx + 1..];
- ret
- }
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- #[inline]
- fn next_back(&mut self) -> Option<&'a [T]> {
- if self.finished {
- return None;
- }
-
- match self.v.iter().rposition(|x| (self.pred)(x)) {
- None => self.finish(),
- Some(idx) => {
- let ret = Some(&self.v[idx + 1..]);
- self.v = &self.v[..idx];
- ret
- }
- }
- }
-}
-
-impl<'a, T, P> SplitIter for Split<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- #[inline]
- fn finish(&mut self) -> Option<&'a [T]> {
- if self.finished {
- None
- } else {
- self.finished = true;
- Some(self.v)
- }
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T, P> FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An iterator over subslices separated by elements that match a predicate
-/// function. Unlike `Split`, it contains the matched part as a terminator
-/// of the subslice.
-///
-/// This struct is created by the [`split_inclusive`] method on [slices].
-///
-/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive
-/// [slices]: ../../std/primitive.slice.html
-#[unstable(feature = "split_inclusive", issue = "72360")]
-pub struct SplitInclusive<'a, T: 'a, P>
-where
- P: FnMut(&T) -> bool,
-{
- v: &'a [T],
- pred: P,
- finished: bool,
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitInclusive<'_, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SplitInclusive")
- .field("v", &self.v)
- .field("finished", &self.finished)
- .finish()
- }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<T, P> Clone for SplitInclusive<'_, T, P>
-where
- P: Clone + FnMut(&T) -> bool,
-{
- fn clone(&self) -> Self {
- SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished }
- }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, T, P> Iterator for SplitInclusive<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- type Item = &'a [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a [T]> {
- if self.finished {
- return None;
- }
-
- let idx =
- self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len());
- if idx == self.v.len() {
- self.finished = true;
- }
- let ret = Some(&self.v[..idx]);
- self.v = &self.v[idx..];
- ret
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) }
- }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- #[inline]
- fn next_back(&mut self) -> Option<&'a [T]> {
- if self.finished {
- return None;
- }
-
- // The last index of self.v is already checked and found to match
- // by the last iteration, so we start searching a new match
- // one index to the left.
- let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] };
- let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0);
- if idx == 0 {
- self.finished = true;
- }
- let ret = Some(&self.v[idx..]);
- self.v = &self.v[..idx];
- ret
- }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<T, P> FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An iterator over the mutable subslices of the vector which are separated
-/// by elements that match `pred`.
-///
-/// This struct is created by the [`split_mut`] method on [slices].
-///
-/// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SplitMut<'a, T: 'a, P>
-where
- P: FnMut(&T) -> bool,
-{
- v: &'a mut [T],
- pred: P,
- finished: bool,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitMut<'_, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish()
- }
-}
-
-impl<'a, T, P> SplitIter for SplitMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- #[inline]
- fn finish(&mut self) -> Option<&'a mut [T]> {
- if self.finished {
- None
- } else {
- self.finished = true;
- Some(mem::replace(&mut self.v, &mut []))
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, P> Iterator for SplitMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- type Item = &'a mut [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut [T]> {
- if self.finished {
- return None;
- }
-
- let idx_opt = {
- // work around borrowck limitations
- let pred = &mut self.pred;
- self.v.iter().position(|x| (*pred)(x))
- };
- match idx_opt {
- None => self.finish(),
- Some(idx) => {
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(idx);
- self.v = &mut tail[1..];
- Some(head)
- }
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.finished {
- (0, Some(0))
- } else {
- // if the predicate doesn't match anything, we yield one slice
- // if it matches every element, we yield len+1 empty slices.
- (1, Some(self.v.len() + 1))
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- #[inline]
- fn next_back(&mut self) -> Option<&'a mut [T]> {
- if self.finished {
- return None;
- }
-
- let idx_opt = {
- // work around borrowck limitations
- let pred = &mut self.pred;
- self.v.iter().rposition(|x| (*pred)(x))
- };
- match idx_opt {
- None => self.finish(),
- Some(idx) => {
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(idx);
- self.v = head;
- Some(&mut tail[1..])
- }
- }
- }
-}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T, P> FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An iterator over the mutable subslices of the vector which are separated
-/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched
-/// parts in the ends of the subslices.
-///
-/// This struct is created by the [`split_inclusive_mut`] method on [slices].
-///
-/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut
-/// [slices]: ../../std/primitive.slice.html
-#[unstable(feature = "split_inclusive", issue = "72360")]
-pub struct SplitInclusiveMut<'a, T: 'a, P>
-where
- P: FnMut(&T) -> bool,
-{
- v: &'a mut [T],
- pred: P,
- finished: bool,
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitInclusiveMut<'_, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SplitInclusiveMut")
- .field("v", &self.v)
- .field("finished", &self.finished)
- .finish()
- }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- type Item = &'a mut [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut [T]> {
- if self.finished {
- return None;
- }
-
- let idx_opt = {
- // work around borrowck limitations
- let pred = &mut self.pred;
- self.v.iter().position(|x| (*pred)(x))
- };
- let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len());
- if idx == self.v.len() {
- self.finished = true;
- }
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(idx);
- self.v = tail;
- Some(head)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.finished {
- (0, Some(0))
- } else {
- // if the predicate doesn't match anything, we yield one slice
- // if it matches every element, we yield len+1 empty slices.
- (1, Some(self.v.len() + 1))
- }
- }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- #[inline]
- fn next_back(&mut self) -> Option<&'a mut [T]> {
- if self.finished {
- return None;
- }
-
- let idx_opt = if self.v.is_empty() {
- None
- } else {
- // work around borrowck limitations
- let pred = &mut self.pred;
-
- // The last index of self.v is already checked and found to match
- // by the last iteration, so we start searching a new match
- // one index to the left.
- let remainder = &self.v[..(self.v.len() - 1)];
- remainder.iter().rposition(|x| (*pred)(x))
- };
- let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0);
- if idx == 0 {
- self.finished = true;
- }
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(idx);
- self.v = head;
- Some(tail)
- }
-}
-
-#[unstable(feature = "split_inclusive", issue = "72360")]
-impl<T, P> FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An iterator over subslices separated by elements that match a predicate
-/// function, starting from the end of the slice.
-///
-/// This struct is created by the [`rsplit`] method on [slices].
-///
-/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`?
-pub struct RSplit<'a, T: 'a, P>
-where
- P: FnMut(&T) -> bool,
-{
- inner: Split<'a, T, P>,
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<T: fmt::Debug, P> fmt::Debug for RSplit<'_, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("RSplit")
- .field("v", &self.inner.v)
- .field("finished", &self.inner.finished)
- .finish()
- }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> Iterator for RSplit<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- type Item = &'a [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a [T]> {
- self.inner.next_back()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.inner.size_hint()
- }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- #[inline]
- fn next_back(&mut self) -> Option<&'a [T]> {
- self.inner.next()
- }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> SplitIter for RSplit<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- #[inline]
- fn finish(&mut self) -> Option<&'a [T]> {
- self.inner.finish()
- }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<T, P> FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An iterator over the subslices of the vector which are separated
-/// by elements that match `pred`, starting from the end of the slice.
-///
-/// This struct is created by the [`rsplit_mut`] method on [slices].
-///
-/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-pub struct RSplitMut<'a, T: 'a, P>
-where
- P: FnMut(&T) -> bool,
-{
- inner: SplitMut<'a, T, P>,
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<T: fmt::Debug, P> fmt::Debug for RSplitMut<'_, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("RSplitMut")
- .field("v", &self.inner.v)
- .field("finished", &self.inner.finished)
- .finish()
- }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> SplitIter for RSplitMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- #[inline]
- fn finish(&mut self) -> Option<&'a mut [T]> {
- self.inner.finish()
- }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> Iterator for RSplitMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- type Item = &'a mut [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut [T]> {
- self.inner.next_back()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.inner.size_hint()
- }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- #[inline]
- fn next_back(&mut self) -> Option<&'a mut [T]> {
- self.inner.next()
- }
-}
-
-#[stable(feature = "slice_rsplit", since = "1.27.0")]
-impl<T, P> FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
-
-/// An private iterator over subslices separated by elements that
-/// match a predicate function, splitting at most a fixed number of
-/// times.
-#[derive(Debug)]
-struct GenericSplitN<I> {
- iter: I,
- count: usize,
-}
-
-impl<T, I: SplitIter<Item = T>> Iterator for GenericSplitN<I> {
- type Item = T;
-
- #[inline]
- fn next(&mut self) -> Option<T> {
- match self.count {
- 0 => None,
- 1 => {
- self.count -= 1;
- self.iter.finish()
- }
- _ => {
- self.count -= 1;
- self.iter.next()
- }
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let (lower, upper_opt) = self.iter.size_hint();
- (lower, upper_opt.map(|upper| cmp::min(self.count, upper)))
- }
-}
-
-/// An iterator over subslices separated by elements that match a predicate
-/// function, limited to a given number of splits.
-///
-/// This struct is created by the [`splitn`] method on [slices].
-///
-/// [`splitn`]: ../../std/primitive.slice.html#method.splitn
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SplitN<'a, T: 'a, P>
-where
- P: FnMut(&T) -> bool,
-{
- inner: GenericSplitN<Split<'a, T, P>>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitN<'_, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SplitN").field("inner", &self.inner).finish()
- }
-}
-
-/// An iterator over subslices separated by elements that match a
-/// predicate function, limited to a given number of splits, starting
-/// from the end of the slice.
-///
-/// This struct is created by the [`rsplitn`] method on [slices].
-///
-/// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct RSplitN<'a, T: 'a, P>
-where
- P: FnMut(&T) -> bool,
-{
- inner: GenericSplitN<RSplit<'a, T, P>>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for RSplitN<'_, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("RSplitN").field("inner", &self.inner).finish()
- }
-}
-
-/// An iterator over subslices separated by elements that match a predicate
-/// function, limited to a given number of splits.
-///
-/// This struct is created by the [`splitn_mut`] method on [slices].
-///
-/// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct SplitNMut<'a, T: 'a, P>
-where
- P: FnMut(&T) -> bool,
-{
- inner: GenericSplitN<SplitMut<'a, T, P>>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitNMut<'_, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SplitNMut").field("inner", &self.inner).finish()
- }
-}
-
-/// An iterator over subslices separated by elements that match a
-/// predicate function, limited to a given number of splits, starting
-/// from the end of the slice.
-///
-/// This struct is created by the [`rsplitn_mut`] method on [slices].
-///
-/// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut
-/// [slices]: ../../std/primitive.slice.html
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct RSplitNMut<'a, T: 'a, P>
-where
- P: FnMut(&T) -> bool,
-{
- inner: GenericSplitN<RSplitMut<'a, T, P>>,
-}
-
-#[stable(feature = "core_impl_debug", since = "1.9.0")]
-impl<T: fmt::Debug, P> fmt::Debug for RSplitNMut<'_, T, P>
-where
- P: FnMut(&T) -> bool,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("RSplitNMut").field("inner", &self.inner).finish()
- }
-}
-
-macro_rules! forward_iterator {
- ($name:ident: $elem:ident, $iter_of:ty) => {
- #[stable(feature = "rust1", since = "1.0.0")]
- impl<'a, $elem, P> Iterator for $name<'a, $elem, P>
- where
- P: FnMut(&T) -> bool,
- {
- type Item = $iter_of;
-
- #[inline]
- fn next(&mut self) -> Option<$iter_of> {
- self.inner.next()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.inner.size_hint()
- }
- }
-
- #[stable(feature = "fused", since = "1.26.0")]
- impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {}
- };
-}
-
-forward_iterator! { SplitN: T, &'a [T] }
-forward_iterator! { RSplitN: T, &'a [T] }
-forward_iterator! { SplitNMut: T, &'a mut [T] }
-forward_iterator! { RSplitNMut: T, &'a mut [T] }
-
-/// An iterator over overlapping subslices of length `size`.
-///
-/// This struct is created by the [`windows`] method on [slices].
-///
-/// [`windows`]: ../../std/primitive.slice.html#method.windows
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Windows<'a, T: 'a> {
- v: &'a [T],
- size: usize,
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for Windows<'_, T> {
- fn clone(&self) -> Self {
- Windows { v: self.v, size: self.size }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> Iterator for Windows<'a, T> {
- type Item = &'a [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a [T]> {
- if self.size > self.v.len() {
- None
- } else {
- let ret = Some(&self.v[..self.size]);
- self.v = &self.v[1..];
- ret
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.size > self.v.len() {
- (0, Some(0))
- } else {
- let size = self.v.len() - self.size + 1;
- (size, Some(size))
- }
- }
-
- #[inline]
- fn count(self) -> usize {
- self.len()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<Self::Item> {
- let (end, overflow) = self.size.overflowing_add(n);
- if end > self.v.len() || overflow {
- self.v = &[];
- None
- } else {
- let nth = &self.v[n..end];
- self.v = &self.v[n + 1..];
- Some(nth)
- }
- }
-
- #[inline]
- fn last(self) -> Option<Self::Item> {
- if self.size > self.v.len() {
- None
- } else {
- let start = self.v.len() - self.size;
- Some(&self.v[start..])
- }
- }
-
- #[doc(hidden)]
- unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
- // SAFETY: since the caller guarantees that `i` is in bounds,
- // which means that `i` cannot overflow an `isize`, and the
- // slice created by `from_raw_parts` is a subslice of `self.v`
- // thus is guaranteed to be valid for the lifetime `'a` of `self.v`.
- unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> DoubleEndedIterator for Windows<'a, T> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a [T]> {
- if self.size > self.v.len() {
- None
- } else {
- let ret = Some(&self.v[self.v.len() - self.size..]);
- self.v = &self.v[..self.v.len() - 1];
- ret
- }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- let (end, overflow) = self.v.len().overflowing_sub(n);
- if end < self.size || overflow {
- self.v = &[];
- None
- } else {
- let ret = &self.v[end - self.size..end];
- self.v = &self.v[..end - 1];
- Some(ret)
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for Windows<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for Windows<'_, T> {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Windows<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
-/// time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last slice
-/// of the iteration will be the remainder.
-///
-/// This struct is created by the [`chunks`] method on [slices].
-///
-/// [`chunks`]: ../../std/primitive.slice.html#method.chunks
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct Chunks<'a, T: 'a> {
- v: &'a [T],
- chunk_size: usize,
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Clone for Chunks<'_, T> {
- fn clone(&self) -> Self {
- Chunks { v: self.v, chunk_size: self.chunk_size }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> Iterator for Chunks<'a, T> {
- type Item = &'a [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a [T]> {
- if self.v.is_empty() {
- None
- } else {
- let chunksz = cmp::min(self.v.len(), self.chunk_size);
- let (fst, snd) = self.v.split_at(chunksz);
- self.v = snd;
- Some(fst)
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.v.is_empty() {
- (0, Some(0))
- } else {
- let n = self.v.len() / self.chunk_size;
- let rem = self.v.len() % self.chunk_size;
- let n = if rem > 0 { n + 1 } else { n };
- (n, Some(n))
- }
- }
-
- #[inline]
- fn count(self) -> usize {
- self.len()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<Self::Item> {
- let (start, overflow) = n.overflowing_mul(self.chunk_size);
- if start >= self.v.len() || overflow {
- self.v = &[];
- None
- } else {
- let end = match start.checked_add(self.chunk_size) {
- Some(sum) => cmp::min(self.v.len(), sum),
- None => self.v.len(),
- };
- let nth = &self.v[start..end];
- self.v = &self.v[end..];
- Some(nth)
- }
- }
-
- #[inline]
- fn last(self) -> Option<Self::Item> {
- if self.v.is_empty() {
- None
- } else {
- let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
- Some(&self.v[start..])
- }
- }
-
- #[doc(hidden)]
- unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
- let start = idx * self.chunk_size;
- let end = match start.checked_add(self.chunk_size) {
- None => self.v.len(),
- Some(end) => cmp::min(end, self.v.len()),
- };
- // SAFETY: the caller guarantees that `i` is in bounds,
- // which means that `start` must be in bounds of the
- // underlying `self.v` slice, and we made sure that `end`
- // is also in bounds of `self.v`. Thus, `start` cannot overflow
- // an `isize`, and the slice constructed by `from_raw_parts`
- // is a subslice of `self.v` which is guaranteed to be valid
- // for the lifetime `'a` of `self.v`.
- unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> DoubleEndedIterator for Chunks<'a, T> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a [T]> {
- if self.v.is_empty() {
- None
- } else {
- let remainder = self.v.len() % self.chunk_size;
- let chunksz = if remainder != 0 { remainder } else { self.chunk_size };
- let (fst, snd) = self.v.split_at(self.v.len() - chunksz);
- self.v = fst;
- Some(snd)
- }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- let len = self.len();
- if n >= len {
- self.v = &[];
- None
- } else {
- let start = (len - 1 - n) * self.chunk_size;
- let end = match start.checked_add(self.chunk_size) {
- Some(res) => cmp::min(res, self.v.len()),
- None => self.v.len(),
- };
- let nth_back = &self.v[start..end];
- self.v = &self.v[..start];
- Some(nth_back)
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for Chunks<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for Chunks<'_, T> {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for Chunks<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
-/// elements at a time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last slice
-/// of the iteration will be the remainder.
-///
-/// This struct is created by the [`chunks_mut`] method on [slices].
-///
-/// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct ChunksMut<'a, T: 'a> {
- v: &'a mut [T],
- chunk_size: usize,
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> Iterator for ChunksMut<'a, T> {
- type Item = &'a mut [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut [T]> {
- if self.v.is_empty() {
- None
- } else {
- let sz = cmp::min(self.v.len(), self.chunk_size);
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(sz);
- self.v = tail;
- Some(head)
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.v.is_empty() {
- (0, Some(0))
- } else {
- let n = self.v.len() / self.chunk_size;
- let rem = self.v.len() % self.chunk_size;
- let n = if rem > 0 { n + 1 } else { n };
- (n, Some(n))
- }
- }
-
- #[inline]
- fn count(self) -> usize {
- self.len()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
- let (start, overflow) = n.overflowing_mul(self.chunk_size);
- if start >= self.v.len() || overflow {
- self.v = &mut [];
- None
- } else {
- let end = match start.checked_add(self.chunk_size) {
- Some(sum) => cmp::min(self.v.len(), sum),
- None => self.v.len(),
- };
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(end);
- let (_, nth) = head.split_at_mut(start);
- self.v = tail;
- Some(nth)
- }
- }
-
- #[inline]
- fn last(self) -> Option<Self::Item> {
- if self.v.is_empty() {
- None
- } else {
- let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size;
- Some(&mut self.v[start..])
- }
- }
-
- #[doc(hidden)]
- unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
- let start = idx * self.chunk_size;
- let end = match start.checked_add(self.chunk_size) {
- None => self.v.len(),
- Some(end) => cmp::min(end, self.v.len()),
- };
- // SAFETY: see comments for `Chunks::get_unchecked`.
- //
- // Also note that the caller also guarantees that we're never called
- // with the same index again, and that no other methods that will
- // access this subslice are called, so it is valid for the returned
- // slice to be mutable.
- unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a mut [T]> {
- if self.v.is_empty() {
- None
- } else {
- let remainder = self.v.len() % self.chunk_size;
- let sz = if remainder != 0 { remainder } else { self.chunk_size };
- let tmp = mem::replace(&mut self.v, &mut []);
- let tmp_len = tmp.len();
- let (head, tail) = tmp.split_at_mut(tmp_len - sz);
- self.v = head;
- Some(tail)
- }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- let len = self.len();
- if n >= len {
- self.v = &mut [];
- None
- } else {
- let start = (len - 1 - n) * self.chunk_size;
- let end = match start.checked_add(self.chunk_size) {
- Some(res) => cmp::min(res, self.v.len()),
- None => self.v.len(),
- };
- let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
- let (head, nth_back) = temp.split_at_mut(start);
- self.v = head;
- Some(nth_back)
- }
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for ChunksMut<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for ChunksMut<'_, T> {}
-
-#[stable(feature = "fused", since = "1.26.0")]
-impl<T> FusedIterator for ChunksMut<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
-/// time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last
-/// up to `chunk_size-1` elements will be omitted but can be retrieved from
-/// the [`remainder`] function from the iterator.
-///
-/// This struct is created by the [`chunks_exact`] method on [slices].
-///
-/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact
-/// [`remainder`]: ChunksExact::remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-pub struct ChunksExact<'a, T: 'a> {
- v: &'a [T],
- rem: &'a [T],
- chunk_size: usize,
-}
-
-impl<'a, T> ChunksExact<'a, T> {
- /// Returns the remainder of the original slice that is not going to be
- /// returned by the iterator. The returned slice has at most `chunk_size-1`
- /// elements.
- #[stable(feature = "chunks_exact", since = "1.31.0")]
- pub fn remainder(&self) -> &'a [T] {
- self.rem
- }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<T> Clone for ChunksExact<'_, T> {
- fn clone(&self) -> Self {
- ChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size }
- }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<'a, T> Iterator for ChunksExact<'a, T> {
- type Item = &'a [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a [T]> {
- if self.v.len() < self.chunk_size {
- None
- } else {
- let (fst, snd) = self.v.split_at(self.chunk_size);
- self.v = snd;
- Some(fst)
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let n = self.v.len() / self.chunk_size;
- (n, Some(n))
- }
-
- #[inline]
- fn count(self) -> usize {
- self.len()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<Self::Item> {
- let (start, overflow) = n.overflowing_mul(self.chunk_size);
- if start >= self.v.len() || overflow {
- self.v = &[];
- None
- } else {
- let (_, snd) = self.v.split_at(start);
- self.v = snd;
- self.next()
- }
- }
-
- #[inline]
- fn last(mut self) -> Option<Self::Item> {
- self.next_back()
- }
-
- #[doc(hidden)]
- unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
- let start = idx * self.chunk_size;
- // SAFETY: mostly identical to `Chunks::get_unchecked`.
- unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
- }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a [T]> {
- if self.v.len() < self.chunk_size {
- None
- } else {
- let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size);
- self.v = fst;
- Some(snd)
- }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- let len = self.len();
- if n >= len {
- self.v = &[];
- None
- } else {
- let start = (len - 1 - n) * self.chunk_size;
- let end = start + self.chunk_size;
- let nth_back = &self.v[start..end];
- self.v = &self.v[..start];
- Some(nth_back)
- }
- }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<T> ExactSizeIterator for ChunksExact<'_, T> {
- fn is_empty(&self) -> bool {
- self.v.is_empty()
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for ChunksExact<'_, T> {}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<T> FusedIterator for ChunksExact<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
-/// elements at a time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last up to
-/// `chunk_size-1` elements will be omitted but can be retrieved from the
-/// [`into_remainder`] function from the iterator.
-///
-/// This struct is created by the [`chunks_exact_mut`] method on [slices].
-///
-/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut
-/// [`into_remainder`]: ChunksExactMut::into_remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-pub struct ChunksExactMut<'a, T: 'a> {
- v: &'a mut [T],
- rem: &'a mut [T],
- chunk_size: usize,
-}
-
-impl<'a, T> ChunksExactMut<'a, T> {
- /// Returns the remainder of the original slice that is not going to be
- /// returned by the iterator. The returned slice has at most `chunk_size-1`
- /// elements.
- #[stable(feature = "chunks_exact", since = "1.31.0")]
- pub fn into_remainder(self) -> &'a mut [T] {
- self.rem
- }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<'a, T> Iterator for ChunksExactMut<'a, T> {
- type Item = &'a mut [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut [T]> {
- if self.v.len() < self.chunk_size {
- None
- } else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(self.chunk_size);
- self.v = tail;
- Some(head)
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let n = self.v.len() / self.chunk_size;
- (n, Some(n))
- }
-
- #[inline]
- fn count(self) -> usize {
- self.len()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
- let (start, overflow) = n.overflowing_mul(self.chunk_size);
- if start >= self.v.len() || overflow {
- self.v = &mut [];
- None
- } else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let (_, snd) = tmp.split_at_mut(start);
- self.v = snd;
- self.next()
- }
- }
-
- #[inline]
- fn last(mut self) -> Option<Self::Item> {
- self.next_back()
- }
-
- #[doc(hidden)]
- unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
- let start = idx * self.chunk_size;
- // SAFETY: see comments for `ChunksMut::get_unchecked`.
- unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
- }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a mut [T]> {
- if self.v.len() < self.chunk_size {
- None
- } else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let tmp_len = tmp.len();
- let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
- self.v = head;
- Some(tail)
- }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- let len = self.len();
- if n >= len {
- self.v = &mut [];
- None
- } else {
- let start = (len - 1 - n) * self.chunk_size;
- let end = start + self.chunk_size;
- let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
- let (head, nth_back) = temp.split_at_mut(start);
- self.v = head;
- Some(nth_back)
- }
- }
-}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<T> ExactSizeIterator for ChunksExactMut<'_, T> {
- fn is_empty(&self) -> bool {
- self.v.is_empty()
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for ChunksExactMut<'_, T> {}
-
-#[stable(feature = "chunks_exact", since = "1.31.0")]
-impl<T> FusedIterator for ChunksExactMut<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a
-/// time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last
-/// up to `N-1` elements will be omitted but can be retrieved from
-/// the [`remainder`] function from the iterator.
-///
-/// This struct is created by the [`array_chunks`] method on [slices].
-///
-/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks
-/// [`remainder`]: ArrayChunks::remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-pub struct ArrayChunks<'a, T: 'a, const N: usize> {
- iter: Iter<'a, [T; N]>,
- rem: &'a [T],
-}
-
-impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
- /// Returns the remainder of the original slice that is not going to be
- /// returned by the iterator. The returned slice has at most `N-1`
- /// elements.
- #[unstable(feature = "array_chunks", issue = "74985")]
- pub fn remainder(&self) -> &'a [T] {
- self.rem
- }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> Clone for ArrayChunks<'_, T, N> {
- fn clone(&self) -> Self {
- ArrayChunks { iter: self.iter.clone(), rem: self.rem }
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> {
- type Item = &'a [T; N];
-
- #[inline]
- fn next(&mut self) -> Option<&'a [T; N]> {
- self.iter.next()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-
- #[inline]
- fn count(self) -> usize {
- self.iter.count()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<Self::Item> {
- self.iter.nth(n)
- }
-
- #[inline]
- fn last(self) -> Option<Self::Item> {
- self.iter.last()
- }
-
- unsafe fn get_unchecked(&mut self, i: usize) -> &'a [T; N] {
- // SAFETY: The safety guarantees of `get_unchecked` are transferred to
- // the caller.
- unsafe { self.iter.get_unchecked(i) }
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a [T; N]> {
- self.iter.next_back()
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- self.iter.nth_back(n)
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> ExactSizeIterator for ArrayChunks<'_, T, N> {
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T, const N: usize> TrustedLen for ArrayChunks<'_, T, N> {}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {}
-
-#[doc(hidden)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements
-/// at a time), starting at the beginning of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last
-/// up to `N-1` elements will be omitted but can be retrieved from
-/// the [`into_remainder`] function from the iterator.
-///
-/// This struct is created by the [`array_chunks_mut`] method on [slices].
-///
-/// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut
-/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-pub struct ArrayChunksMut<'a, T: 'a, const N: usize> {
- iter: IterMut<'a, [T; N]>,
- rem: &'a mut [T],
-}
-
-impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
- /// Returns the remainder of the original slice that is not going to be
- /// returned by the iterator. The returned slice has at most `N-1`
- /// elements.
- #[unstable(feature = "array_chunks", issue = "74985")]
- pub fn into_remainder(self) -> &'a mut [T] {
- self.rem
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> {
- type Item = &'a mut [T; N];
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut [T; N]> {
- self.iter.next()
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-
- #[inline]
- fn count(self) -> usize {
- self.iter.count()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<Self::Item> {
- self.iter.nth(n)
- }
-
- #[inline]
- fn last(self) -> Option<Self::Item> {
- self.iter.last()
- }
-
- unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut [T; N] {
- // SAFETY: The safety guarantees of `get_unchecked` are transferred to
- // the caller.
- unsafe { self.iter.get_unchecked(i) }
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a mut [T; N]> {
- self.iter.next_back()
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- self.iter.nth_back(n)
- }
-}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> ExactSizeIterator for ArrayChunksMut<'_, T, N> {
- fn is_empty(&self) -> bool {
- self.iter.is_empty()
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T, const N: usize> TrustedLen for ArrayChunksMut<'_, T, N> {}
-
-#[unstable(feature = "array_chunks", issue = "74985")]
-impl<T, const N: usize> FusedIterator for ArrayChunksMut<'_, T, N> {}
-
-#[doc(hidden)]
-#[unstable(feature = "array_chunks", issue = "74985")]
-unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
-/// time), starting at the end of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last slice
-/// of the iteration will be the remainder.
-///
-/// This struct is created by the [`rchunks`] method on [slices].
-///
-/// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rchunks", since = "1.31.0")]
-pub struct RChunks<'a, T: 'a> {
- v: &'a [T],
- chunk_size: usize,
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> Clone for RChunks<'_, T> {
- fn clone(&self) -> Self {
- RChunks { v: self.v, chunk_size: self.chunk_size }
- }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> Iterator for RChunks<'a, T> {
- type Item = &'a [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a [T]> {
- if self.v.is_empty() {
- None
- } else {
- let chunksz = cmp::min(self.v.len(), self.chunk_size);
- let (fst, snd) = self.v.split_at(self.v.len() - chunksz);
- self.v = fst;
- Some(snd)
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.v.is_empty() {
- (0, Some(0))
- } else {
- let n = self.v.len() / self.chunk_size;
- let rem = self.v.len() % self.chunk_size;
- let n = if rem > 0 { n + 1 } else { n };
- (n, Some(n))
- }
- }
-
- #[inline]
- fn count(self) -> usize {
- self.len()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<Self::Item> {
- let (end, overflow) = n.overflowing_mul(self.chunk_size);
- if end >= self.v.len() || overflow {
- self.v = &[];
- None
- } else {
- // Can't underflow because of the check above
- let end = self.v.len() - end;
- let start = match end.checked_sub(self.chunk_size) {
- Some(sum) => sum,
- None => 0,
- };
- let nth = &self.v[start..end];
- self.v = &self.v[0..start];
- Some(nth)
- }
- }
-
- #[inline]
- fn last(self) -> Option<Self::Item> {
- if self.v.is_empty() {
- None
- } else {
- let rem = self.v.len() % self.chunk_size;
- let end = if rem == 0 { self.chunk_size } else { rem };
- Some(&self.v[0..end])
- }
- }
-
- #[doc(hidden)]
- unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
- let end = self.v.len() - idx * self.chunk_size;
- let start = match end.checked_sub(self.chunk_size) {
- None => 0,
- Some(start) => start,
- };
- // SAFETY: mostly identical to `Chunks::get_unchecked`.
- unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) }
- }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for RChunks<'a, T> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a [T]> {
- if self.v.is_empty() {
- None
- } else {
- let remainder = self.v.len() % self.chunk_size;
- let chunksz = if remainder != 0 { remainder } else { self.chunk_size };
- let (fst, snd) = self.v.split_at(chunksz);
- self.v = snd;
- Some(fst)
- }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- let len = self.len();
- if n >= len {
- self.v = &[];
- None
- } else {
- // can't underflow because `n < len`
- let offset_from_end = (len - 1 - n) * self.chunk_size;
- let end = self.v.len() - offset_from_end;
- let start = end.saturating_sub(self.chunk_size);
- let nth_back = &self.v[start..end];
- self.v = &self.v[end..];
- Some(nth_back)
- }
- }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> ExactSizeIterator for RChunks<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for RChunks<'_, T> {}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> FusedIterator for RChunks<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
-/// elements at a time), starting at the end of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last slice
-/// of the iteration will be the remainder.
-///
-/// This struct is created by the [`rchunks_mut`] method on [slices].
-///
-/// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rchunks", since = "1.31.0")]
-pub struct RChunksMut<'a, T: 'a> {
- v: &'a mut [T],
- chunk_size: usize,
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> Iterator for RChunksMut<'a, T> {
- type Item = &'a mut [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut [T]> {
- if self.v.is_empty() {
- None
- } else {
- let sz = cmp::min(self.v.len(), self.chunk_size);
- let tmp = mem::replace(&mut self.v, &mut []);
- let tmp_len = tmp.len();
- let (head, tail) = tmp.split_at_mut(tmp_len - sz);
- self.v = head;
- Some(tail)
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- if self.v.is_empty() {
- (0, Some(0))
- } else {
- let n = self.v.len() / self.chunk_size;
- let rem = self.v.len() % self.chunk_size;
- let n = if rem > 0 { n + 1 } else { n };
- (n, Some(n))
- }
- }
-
- #[inline]
- fn count(self) -> usize {
- self.len()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
- let (end, overflow) = n.overflowing_mul(self.chunk_size);
- if end >= self.v.len() || overflow {
- self.v = &mut [];
- None
- } else {
- // Can't underflow because of the check above
- let end = self.v.len() - end;
- let start = match end.checked_sub(self.chunk_size) {
- Some(sum) => sum,
- None => 0,
- };
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(start);
- let (nth, _) = tail.split_at_mut(end - start);
- self.v = head;
- Some(nth)
- }
- }
-
- #[inline]
- fn last(self) -> Option<Self::Item> {
- if self.v.is_empty() {
- None
- } else {
- let rem = self.v.len() % self.chunk_size;
- let end = if rem == 0 { self.chunk_size } else { rem };
- Some(&mut self.v[0..end])
- }
- }
-
- #[doc(hidden)]
- unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
- let end = self.v.len() - idx * self.chunk_size;
- let start = match end.checked_sub(self.chunk_size) {
- None => 0,
- Some(start) => start,
- };
- // SAFETY: see comments for `RChunks::get_unchecked` and `ChunksMut::get_unchecked`
- unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) }
- }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a mut [T]> {
- if self.v.is_empty() {
- None
- } else {
- let remainder = self.v.len() % self.chunk_size;
- let sz = if remainder != 0 { remainder } else { self.chunk_size };
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(sz);
- self.v = tail;
- Some(head)
- }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- let len = self.len();
- if n >= len {
- self.v = &mut [];
- None
- } else {
- // can't underflow because `n < len`
- let offset_from_end = (len - 1 - n) * self.chunk_size;
- let end = self.v.len() - offset_from_end;
- let start = end.saturating_sub(self.chunk_size);
- let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
- let (_, nth_back) = tmp.split_at_mut(start);
- self.v = tail;
- Some(nth_back)
- }
- }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> ExactSizeIterator for RChunksMut<'_, T> {}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for RChunksMut<'_, T> {}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> FusedIterator for RChunksMut<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a
-/// time), starting at the end of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last
-/// up to `chunk_size-1` elements will be omitted but can be retrieved from
-/// the [`remainder`] function from the iterator.
-///
-/// This struct is created by the [`rchunks_exact`] method on [slices].
-///
-/// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact
-/// [`remainder`]: ChunksExact::remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rchunks", since = "1.31.0")]
-pub struct RChunksExact<'a, T: 'a> {
- v: &'a [T],
- rem: &'a [T],
- chunk_size: usize,
-}
-
-impl<'a, T> RChunksExact<'a, T> {
- /// Returns the remainder of the original slice that is not going to be
- /// returned by the iterator. The returned slice has at most `chunk_size-1`
- /// elements.
- #[stable(feature = "rchunks", since = "1.31.0")]
- pub fn remainder(&self) -> &'a [T] {
- self.rem
- }
-}
-
-// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> Clone for RChunksExact<'a, T> {
- fn clone(&self) -> RChunksExact<'a, T> {
- RChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size }
- }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> Iterator for RChunksExact<'a, T> {
- type Item = &'a [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a [T]> {
- if self.v.len() < self.chunk_size {
- None
- } else {
- let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size);
- self.v = fst;
- Some(snd)
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let n = self.v.len() / self.chunk_size;
- (n, Some(n))
- }
-
- #[inline]
- fn count(self) -> usize {
- self.len()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<Self::Item> {
- let (end, overflow) = n.overflowing_mul(self.chunk_size);
- if end >= self.v.len() || overflow {
- self.v = &[];
- None
- } else {
- let (fst, _) = self.v.split_at(self.v.len() - end);
- self.v = fst;
- self.next()
- }
- }
-
- #[inline]
- fn last(mut self) -> Option<Self::Item> {
- self.next_back()
- }
-
- #[doc(hidden)]
- unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
- let end = self.v.len() - idx * self.chunk_size;
- let start = end - self.chunk_size;
- // SAFETY:
- // SAFETY: mostmy identical to `Chunks::get_unchecked`.
- unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) }
- }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a [T]> {
- if self.v.len() < self.chunk_size {
- None
- } else {
- let (fst, snd) = self.v.split_at(self.chunk_size);
- self.v = snd;
- Some(fst)
- }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- let len = self.len();
- if n >= len {
- self.v = &[];
- None
- } else {
- // now that we know that `n` corresponds to a chunk,
- // none of these operations can underflow/overflow
- let offset = (len - n) * self.chunk_size;
- let start = self.v.len() - offset;
- let end = start + self.chunk_size;
- let nth_back = &self.v[start..end];
- self.v = &self.v[end..];
- Some(nth_back)
- }
- }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> {
- fn is_empty(&self) -> bool {
- self.v.is_empty()
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for RChunksExact<'_, T> {}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> FusedIterator for RChunksExact<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size`
-/// elements at a time), starting at the end of the slice.
-///
-/// When the slice len is not evenly divided by the chunk size, the last up to
-/// `chunk_size-1` elements will be omitted but can be retrieved from the
-/// [`into_remainder`] function from the iterator.
-///
-/// This struct is created by the [`rchunks_exact_mut`] method on [slices].
-///
-/// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut
-/// [`into_remainder`]: ChunksExactMut::into_remainder
-/// [slices]: ../../std/primitive.slice.html
-#[derive(Debug)]
-#[stable(feature = "rchunks", since = "1.31.0")]
-pub struct RChunksExactMut<'a, T: 'a> {
- v: &'a mut [T],
- rem: &'a mut [T],
- chunk_size: usize,
-}
-
-impl<'a, T> RChunksExactMut<'a, T> {
- /// Returns the remainder of the original slice that is not going to be
- /// returned by the iterator. The returned slice has at most `chunk_size-1`
- /// elements.
- #[stable(feature = "rchunks", since = "1.31.0")]
- pub fn into_remainder(self) -> &'a mut [T] {
- self.rem
- }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> Iterator for RChunksExactMut<'a, T> {
- type Item = &'a mut [T];
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut [T]> {
- if self.v.len() < self.chunk_size {
- None
- } else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let tmp_len = tmp.len();
- let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size);
- self.v = head;
- Some(tail)
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- let n = self.v.len() / self.chunk_size;
- (n, Some(n))
- }
-
- #[inline]
- fn count(self) -> usize {
- self.len()
- }
-
- #[inline]
- fn nth(&mut self, n: usize) -> Option<&'a mut [T]> {
- let (end, overflow) = n.overflowing_mul(self.chunk_size);
- if end >= self.v.len() || overflow {
- self.v = &mut [];
- None
- } else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let tmp_len = tmp.len();
- let (fst, _) = tmp.split_at_mut(tmp_len - end);
- self.v = fst;
- self.next()
- }
- }
-
- #[inline]
- fn last(mut self) -> Option<Self::Item> {
- self.next_back()
- }
-
- #[doc(hidden)]
- unsafe fn get_unchecked(&mut self, idx: usize) -> Self::Item {
- let end = self.v.len() - idx * self.chunk_size;
- let start = end - self.chunk_size;
- // SAFETY: see comments for `RChunksMut::get_unchecked`.
- unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) }
- }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a mut [T]> {
- if self.v.len() < self.chunk_size {
- None
- } else {
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(self.chunk_size);
- self.v = tail;
- Some(head)
- }
- }
-
- #[inline]
- fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
- let len = self.len();
- if n >= len {
- self.v = &mut [];
- None
- } else {
- // now that we know that `n` corresponds to a chunk,
- // none of these operations can underflow/overflow
- let offset = (len - n) * self.chunk_size;
- let start = self.v.len() - offset;
- let end = start + self.chunk_size;
- let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end);
- let (_, nth_back) = tmp.split_at_mut(start);
- self.v = tail;
- Some(nth_back)
- }
- }
-}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> ExactSizeIterator for RChunksExactMut<'_, T> {
- fn is_empty(&self) -> bool {
- self.v.is_empty()
- }
-}
-
-#[unstable(feature = "trusted_len", issue = "37572")]
-unsafe impl<T> TrustedLen for RChunksExactMut<'_, T> {}
-
-#[stable(feature = "rchunks", since = "1.31.0")]
-impl<T> FusedIterator for RChunksExactMut<'_, T> {}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-//
-// Free functions
-//
-
-/// Forms a slice from a pointer and a length.
-///
-/// The `len` argument is the number of **elements**, not the number of bytes.
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `data` must be [valid] for reads for `len * mem::size_of::<T>()` many bytes,
-/// and it must be properly aligned. This means in particular:
-///
-/// * The entire memory range of this slice must be contained within a single allocated object!
-/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
-/// for an example incorrectly not taking this into account.
-/// * `data` must be non-null and aligned even for zero-length slices. One
-/// reason for this is that enum layout optimizations may rely on references
-/// (including slices of any length) being aligned and non-null to distinguish
-/// them from other data. You can obtain a pointer that is usable as `data`
-/// for zero-length slices using [`NonNull::dangling()`].
-///
-/// * The memory referenced by the returned slice must not be mutated for the duration
-/// of lifetime `'a`, except inside an `UnsafeCell`.
-///
-/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
-/// See the safety documentation of [`pointer::offset`].
-///
-/// # Caveat
-///
-/// The lifetime for the returned slice is inferred from its usage. To
-/// prevent accidental misuse, it's suggested to tie the lifetime to whichever
-/// source lifetime is safe in the context, such as by providing a helper
-/// function taking the lifetime of a host value for the slice, or by explicit
-/// annotation.
-///
-/// # Examples
-///
-/// ```
-/// use std::slice;
-///
-/// // manifest a slice for a single element
-/// let x = 42;
-/// let ptr = &x as *const _;
-/// let slice = unsafe { slice::from_raw_parts(ptr, 1) };
-/// assert_eq!(slice[0], 42);
-/// ```
-///
-/// ### Incorrect usage
-///
-/// The following `join_slices` function is **unsound** ⚠️
-///
-/// ```rust,no_run
-/// use std::slice;
-///
-/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
-/// let fst_end = fst.as_ptr().wrapping_add(fst.len());
-/// let snd_start = snd.as_ptr();
-/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
-/// unsafe {
-/// // The assertion above ensures `fst` and `snd` are contiguous, but they might
-/// // still be contained within _different allocated objects_, in which case
-/// // creating this slice is undefined behavior.
-/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
-/// }
-/// }
-///
-/// fn main() {
-/// // `a` and `b` are different allocated objects...
-/// let a = 42;
-/// let b = 27;
-/// // ... which may nevertheless be laid out contiguously in memory: | a | b |
-/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
-/// }
-/// ```
-///
-/// [valid]: ptr#safety
-/// [`NonNull::dangling()`]: ptr::NonNull::dangling
-/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
-#[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
- debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
- debug_assert!(
- mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
- "attempt to create slice covering at least half the address space"
- );
- // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
- unsafe { &*ptr::slice_from_raw_parts(data, len) }
-}
-
-/// Performs the same functionality as [`from_raw_parts`], except that a
-/// mutable slice is returned.
-///
-/// # Safety
-///
-/// Behavior is undefined if any of the following conditions are violated:
-///
-/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::<T>()` many bytes,
-/// and it must be properly aligned. This means in particular:
-///
-/// * The entire memory range of this slice must be contained within a single allocated object!
-/// Slices can never span across multiple allocated objects.
-/// * `data` must be non-null and aligned even for zero-length slices. One
-/// reason for this is that enum layout optimizations may rely on references
-/// (including slices of any length) being aligned and non-null to distinguish
-/// them from other data. You can obtain a pointer that is usable as `data`
-/// for zero-length slices using [`NonNull::dangling()`].
-///
-/// * The memory referenced by the returned slice must not be accessed through any other pointer
-/// (not derived from the return value) for the duration of lifetime `'a`.
-/// Both read and write accesses are forbidden.
-///
-/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
-/// See the safety documentation of [`pointer::offset`].
-///
-/// [valid]: ptr#safety
-/// [`NonNull::dangling()`]: ptr::NonNull::dangling
-/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
-#[inline]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
- debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
- debug_assert!(
- mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
- "attempt to create slice covering at least half the address space"
- );
- // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
- unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
-}
-
-/// Converts a reference to T into a slice of length 1 (without copying).
-#[stable(feature = "from_ref", since = "1.28.0")]
-pub fn from_ref<T>(s: &T) -> &[T] {
- // SAFETY: a reference is guaranteed to be valid for reads. The returned
- // reference cannot be mutated as it is an immutable reference.
- // `mem::size_of::<T>()` cannot be larger than `isize::MAX`.
- // Thus the call to `from_raw_parts` is safe.
- unsafe { from_raw_parts(s, 1) }
-}
-
-/// Converts a reference to T into a slice of length 1 (without copying).
-#[stable(feature = "from_ref", since = "1.28.0")]
-pub fn from_mut<T>(s: &mut T) -> &mut [T] {
- // SAFETY: a mutable reference is guaranteed to be valid for writes.
- // The reference cannot be accessed by another pointer as it is an mutable reference.
- // `mem::size_of::<T>()` cannot be larger than `isize::MAX`.
- // Thus the call to `from_raw_parts_mut` is safe.
- unsafe { from_raw_parts_mut(s, 1) }
-}
-
-// This function is public only because there is no other way to unit test heapsort.
-#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")]
-#[doc(hidden)]
-pub fn heapsort<T, F>(v: &mut [T], mut is_less: F)
-where
- F: FnMut(&T, &T) -> bool,
-{
- sort::heapsort(v, &mut is_less);
-}
-
-//
-// Comparison traits
-//
-
-extern "C" {
- /// Calls implementation provided memcmp.
- ///
- /// Interprets the data as u8.
- ///
- /// Returns 0 for equal, < 0 for less than and > 0 for greater
- /// than.
- // FIXME(#32610): Return type should be c_int
- fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32;
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<A, B> PartialEq<[B]> for [A]
-where
- A: PartialEq<B>,
-{
- fn eq(&self, other: &[B]) -> bool {
- SlicePartialEq::equal(self, other)
- }
-
- fn ne(&self, other: &[B]) -> bool {
- SlicePartialEq::not_equal(self, other)
- }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq> Eq for [T] {}
-
-/// Implements comparison of vectors lexicographically.
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> Ord for [T] {
- fn cmp(&self, other: &[T]) -> Ordering {
- SliceOrd::compare(self, other)
- }
-}
-
-/// Implements comparison of vectors lexicographically.
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialOrd> PartialOrd for [T] {
- fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
- SlicePartialOrd::partial_compare(self, other)
- }
-}
-
-#[doc(hidden)]
-// intermediate trait for specialization of slice's PartialEq
-trait SlicePartialEq<B> {
- fn equal(&self, other: &[B]) -> bool;
-
- fn not_equal(&self, other: &[B]) -> bool {
- !self.equal(other)
- }
-}
-
-// Generic slice equality
-impl<A, B> SlicePartialEq<B> for [A]
-where
- A: PartialEq<B>,
-{
- default fn equal(&self, other: &[B]) -> bool {
- if self.len() != other.len() {
- return false;
- }
-
- self.iter().zip(other.iter()).all(|(x, y)| x == y)
- }
-}
-
-// Use an equal-pointer optimization when types are `Eq`
-// We can't make `A` and `B` the same type because `min_specialization` won't
-// allow it.
-impl<A, B> SlicePartialEq<B> for [A]
-where
- A: MarkerEq<B>,
-{
- default fn equal(&self, other: &[B]) -> bool {
- if self.len() != other.len() {
- return false;
- }
-
- // While performance would suffer if `guaranteed_eq` just returned `false`
- // for all arguments, correctness and return value of this function are not affected.
- if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
- return true;
- }
-
- self.iter().zip(other.iter()).all(|(x, y)| x == y)
- }
-}
-
-// Use memcmp for bytewise equality when the types allow
-impl<A, B> SlicePartialEq<B> for [A]
-where
- A: BytewiseEquality<B>,
-{
- fn equal(&self, other: &[B]) -> bool {
- if self.len() != other.len() {
- return false;
- }
-
- // While performance would suffer if `guaranteed_eq` just returned `false`
- // for all arguments, correctness and return value of this function are not affected.
- if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) {
- return true;
- }
- // SAFETY: `self` and `other` are references and are thus guaranteed to be valid.
- // The two slices have been checked to have the same size above.
- unsafe {
- let size = mem::size_of_val(self);
- memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
- }
- }
-}
-
-#[doc(hidden)]
-// intermediate trait for specialization of slice's PartialOrd
-trait SlicePartialOrd: Sized {
- fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
-}
-
-impl<A: PartialOrd> SlicePartialOrd for A {
- default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
- let l = cmp::min(left.len(), right.len());
-
- // Slice to the loop iteration range to enable bound check
- // elimination in the compiler
- let lhs = &left[..l];
- let rhs = &right[..l];
-
- for i in 0..l {
- match lhs[i].partial_cmp(&rhs[i]) {
- Some(Ordering::Equal) => (),
- non_eq => return non_eq,
- }
- }
-
- left.len().partial_cmp(&right.len())
- }
-}
-
-// This is the impl that we would like to have. Unfortunately it's not sound.
-// See `partial_ord_slice.rs`.
-/*
-impl<A> SlicePartialOrd for A
-where
- A: Ord,
-{
- default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
- Some(SliceOrd::compare(left, right))
- }
-}
-*/
-
-impl<A: AlwaysApplicableOrd> SlicePartialOrd for A {
- fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
- Some(SliceOrd::compare(left, right))
- }
-}
-
-#[rustc_specialization_trait]
-trait AlwaysApplicableOrd: SliceOrd + Ord {}
-
-macro_rules! always_applicable_ord {
- ($([$($p:tt)*] $t:ty,)*) => {
- $(impl<$($p)*> AlwaysApplicableOrd for $t {})*
- }
-}
-
-always_applicable_ord! {
- [] u8, [] u16, [] u32, [] u64, [] u128, [] usize,
- [] i8, [] i16, [] i32, [] i64, [] i128, [] isize,
- [] bool, [] char,
- [T: ?Sized] *const T, [T: ?Sized] *mut T,
- [T: AlwaysApplicableOrd] &T,
- [T: AlwaysApplicableOrd] &mut T,
- [T: AlwaysApplicableOrd] Option<T>,
-}
-
-#[doc(hidden)]
-// intermediate trait for specialization of slice's Ord
-trait SliceOrd: Sized {
- fn compare(left: &[Self], right: &[Self]) -> Ordering;
-}
-
-impl<A: Ord> SliceOrd for A {
- default fn compare(left: &[Self], right: &[Self]) -> Ordering {
- let l = cmp::min(left.len(), right.len());
-
- // Slice to the loop iteration range to enable bound check
- // elimination in the compiler
- let lhs = &left[..l];
- let rhs = &right[..l];
-
- for i in 0..l {
- match lhs[i].cmp(&rhs[i]) {
- Ordering::Equal => (),
- non_eq => return non_eq,
- }
- }
-
- left.len().cmp(&right.len())
- }
-}
-
-// memcmp compares a sequence of unsigned bytes lexicographically.
-// this matches the order we want for [u8], but no others (not even [i8]).
-impl SliceOrd for u8 {
- #[inline]
- fn compare(left: &[Self], right: &[Self]) -> Ordering {
- let order =
- // SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
- // We use the minimum of both lengths which guarantees that both regions are
- // valid for reads in that interval.
- unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) };
- if order == 0 {
- left.len().cmp(&right.len())
- } else if order < 0 {
- Less
- } else {
- Greater
- }
- }
-}
-
-// Hack to allow specializing on `Eq` even though `Eq` has a method.
-#[rustc_unsafe_specialization_marker]
-trait MarkerEq<T>: PartialEq<T> {}
-
-impl<T: Eq> MarkerEq<T> for T {}
-
-#[doc(hidden)]
-/// Trait implemented for types that can be compared for equality using
-/// their bytewise representation
-#[rustc_specialization_trait]
-trait BytewiseEquality<T>: MarkerEq<T> + Copy {}
-
-macro_rules! impl_marker_for {
- ($traitname:ident, $($ty:ty)*) => {
- $(
- impl $traitname<$ty> for $ty { }
- )*
- }
-}
-
-impl_marker_for!(BytewiseEquality,
- u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool);
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-#[doc(hidden)]
-#[unstable(feature = "trusted_random_access", issue = "none")]
-unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> {
- fn may_have_side_effect() -> bool {
- false
- }
-}
-
-trait SliceContains: Sized {
- fn slice_contains(&self, x: &[Self]) -> bool;
-}
-
-impl<T> SliceContains for T
-where
- T: PartialEq,
-{
- default fn slice_contains(&self, x: &[Self]) -> bool {
- x.iter().any(|y| *y == *self)
- }
-}
-
-impl SliceContains for u8 {
- fn slice_contains(&self, x: &[Self]) -> bool {
- memchr::memchr(*self, x).is_some()
- }
-}
-
-impl SliceContains for i8 {
- fn slice_contains(&self, x: &[Self]) -> bool {
- let byte = *self as u8;
- // SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()`
- // as `*const u8` is safe. The `x.as_ptr()` comes from a reference and is thus guaranteed
- // to be valid for reads for the length of the slice `x.len()`, which cannot be larger
- // than `isize::MAX`. The returned slice is never mutated.
- let bytes: &[u8] = unsafe { from_raw_parts(x.as_ptr() as *const u8, x.len()) };
- memchr::memchr(byte, bytes).is_some()
- }
-}
--- /dev/null
+//! Free functions to create `&[T]` and `&mut [T]`.
+
+use crate::intrinsics::is_aligned_and_not_null;
+use crate::mem;
+use crate::ptr;
+
+/// Forms a slice from a pointer and a length.
+///
+/// The `len` argument is the number of **elements**, not the number of bytes.
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `data` must be [valid] for reads for `len * mem::size_of::<T>()` many bytes,
+/// and it must be properly aligned. This means in particular:
+///
+/// * The entire memory range of this slice must be contained within a single allocated object!
+/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage)
+/// for an example incorrectly not taking this into account.
+/// * `data` must be non-null and aligned even for zero-length slices. One
+/// reason for this is that enum layout optimizations may rely on references
+/// (including slices of any length) being aligned and non-null to distinguish
+/// them from other data. You can obtain a pointer that is usable as `data`
+/// for zero-length slices using [`NonNull::dangling()`].
+///
+/// * `data` must point to `len` consecutive properly initialized values of type `T`.
+///
+/// * The memory referenced by the returned slice must not be mutated for the duration
+/// of lifetime `'a`, except inside an `UnsafeCell`.
+///
+/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+/// See the safety documentation of [`pointer::offset`].
+///
+/// # Caveat
+///
+/// The lifetime for the returned slice is inferred from its usage. To
+/// prevent accidental misuse, it's suggested to tie the lifetime to whichever
+/// source lifetime is safe in the context, such as by providing a helper
+/// function taking the lifetime of a host value for the slice, or by explicit
+/// annotation.
+///
+/// # Examples
+///
+/// ```
+/// use std::slice;
+///
+/// // manifest a slice for a single element
+/// let x = 42;
+/// let ptr = &x as *const _;
+/// let slice = unsafe { slice::from_raw_parts(ptr, 1) };
+/// assert_eq!(slice[0], 42);
+/// ```
+///
+/// ### Incorrect usage
+///
+/// The following `join_slices` function is **unsound** ⚠️
+///
+/// ```rust,no_run
+/// use std::slice;
+///
+/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] {
+/// let fst_end = fst.as_ptr().wrapping_add(fst.len());
+/// let snd_start = snd.as_ptr();
+/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!");
+/// unsafe {
+/// // The assertion above ensures `fst` and `snd` are contiguous, but they might
+/// // still be contained within _different allocated objects_, in which case
+/// // creating this slice is undefined behavior.
+/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len())
+/// }
+/// }
+///
+/// fn main() {
+/// // `a` and `b` are different allocated objects...
+/// let a = 42;
+/// let b = 27;
+/// // ... which may nevertheless be laid out contiguously in memory: | a | b |
+/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB
+/// }
+/// ```
+///
+/// [valid]: ptr#safety
+/// [`NonNull::dangling()`]: ptr::NonNull::dangling
+/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
+ debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
+ debug_assert!(
+ mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
+ "attempt to create slice covering at least half the address space"
+ );
+ // SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
+ unsafe { &*ptr::slice_from_raw_parts(data, len) }
+}
+
+/// Performs the same functionality as [`from_raw_parts`], except that a
+/// mutable slice is returned.
+///
+/// # Safety
+///
+/// Behavior is undefined if any of the following conditions are violated:
+///
+/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::<T>()` many bytes,
+/// and it must be properly aligned. This means in particular:
+///
+/// * The entire memory range of this slice must be contained within a single allocated object!
+/// Slices can never span across multiple allocated objects.
+/// * `data` must be non-null and aligned even for zero-length slices. One
+/// reason for this is that enum layout optimizations may rely on references
+/// (including slices of any length) being aligned and non-null to distinguish
+/// them from other data. You can obtain a pointer that is usable as `data`
+/// for zero-length slices using [`NonNull::dangling()`].
+///
+/// * `data` must point to `len` consecutive properly initialized values of type `T`.
+///
+/// * The memory referenced by the returned slice must not be accessed through any other pointer
+/// (not derived from the return value) for the duration of lifetime `'a`.
+/// Both read and write accesses are forbidden.
+///
+/// * The total size `len * mem::size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+/// See the safety documentation of [`pointer::offset`].
+///
+/// [valid]: ptr#safety
+/// [`NonNull::dangling()`]: ptr::NonNull::dangling
+/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset
+#[inline]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
+ debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
+ debug_assert!(
+ mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
+ "attempt to create slice covering at least half the address space"
+ );
+ // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
+ unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
+}
+
+/// Converts a reference to T into a slice of length 1 (without copying).
+#[stable(feature = "from_ref", since = "1.28.0")]
+pub fn from_ref<T>(s: &T) -> &[T] {
+ // SAFETY: a reference is guaranteed to be valid for reads. The returned
+ // reference cannot be mutated as it is an immutable reference.
+ // `mem::size_of::<T>()` cannot be larger than `isize::MAX`.
+ // Thus the call to `from_raw_parts` is safe.
+ unsafe { from_raw_parts(s, 1) }
+}
+
+/// Converts a reference to T into a slice of length 1 (without copying).
+#[stable(feature = "from_ref", since = "1.28.0")]
+pub fn from_mut<T>(s: &mut T) -> &mut [T] {
+ // SAFETY: a mutable reference is guaranteed to be valid for writes.
+ // The reference cannot be accessed by another pointer as it is an mutable reference.
+ // `mem::size_of::<T>()` cannot be larger than `isize::MAX`.
+ // Thus the call to `from_raw_parts_mut` is safe.
+ unsafe { from_raw_parts_mut(s, 1) }
+}
/// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case.
#[cold]
-pub fn heapsort<T, F>(v: &mut [T], is_less: &mut F)
+#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")]
+pub fn heapsort<T, F>(v: &mut [T], mut is_less: F)
where
F: FnMut(&T, &T) -> bool,
{
use crate::cell::UnsafeCell;
use crate::fmt;
use crate::intrinsics;
+use crate::mem::align_of;
use crate::hint::spin_loop;
unsafe { &mut *(self.v.get() as *mut bool) }
}
+ /// Get atomic access to a `&mut bool`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(atomic_from_mut)]
+ /// use std::sync::atomic::{AtomicBool, Ordering};
+ ///
+ /// let mut some_bool = true;
+ /// let a = AtomicBool::from_mut(&mut some_bool);
+ /// a.store(false, Ordering::Relaxed);
+ /// assert_eq!(some_bool, false);
+ /// ```
+ #[inline]
+ #[unstable(feature = "atomic_from_mut", issue = "76314")]
+ pub fn from_mut(v: &mut bool) -> &Self {
+ // SAFETY: the mutable reference guarantees unique ownership, and
+ // alignment of both `bool` and `Self` is 1.
+ unsafe { &*(v as *mut bool as *mut Self) }
+ }
+
/// Consumes the atomic and returns the contained value.
///
/// This is safe because passing `self` by value guarantees that no other threads are
unsafe { &mut *self.p.get() }
}
+ /// Get atomic access to a pointer.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(atomic_from_mut)]
+ /// use std::sync::atomic::{AtomicPtr, Ordering};
+ ///
+ /// let mut some_ptr = &mut 123 as *mut i32;
+ /// let a = AtomicPtr::from_mut(&mut some_ptr);
+ /// a.store(&mut 456, Ordering::Relaxed);
+ /// assert_eq!(unsafe { *some_ptr }, 456);
+ /// ```
+ #[inline]
+ #[unstable(feature = "atomic_from_mut", issue = "76314")]
+ pub fn from_mut(v: &mut *mut T) -> &Self {
+ let [] = [(); align_of::<AtomicPtr<()>>() - align_of::<*mut ()>()];
+ // SAFETY:
+ // - the mutable reference guarantees unique ownership.
+ // - the alignment of `*mut T` and `Self` is the same on all platforms
+ // supported by rust, as verified above.
+ unsafe { &*(v as *mut *mut T as *mut Self) }
+ }
+
/// Consumes the atomic and returns the contained value.
///
/// This is safe because passing `self` by value guarantees that no other threads are
}
}
+#[allow(unused_macros)] // This macro ends up being unused on some architectures.
+macro_rules! if_not_8_bit {
+ (u8, $($tt:tt)*) => { "" };
+ (i8, $($tt:tt)*) => { "" };
+ ($_:ident, $($tt:tt)*) => { $($tt)* };
+}
+
#[cfg(target_has_atomic_load_store = "8")]
macro_rules! atomic_int {
($cfg_cas:meta,
$stable_nand:meta,
$const_stable:meta,
$stable_init_const:meta,
- $s_int_type:expr, $int_ref:expr,
+ $(from_mut: cfg($from_mut_cfg:meta),)?
+ $s_int_type:literal, $int_ref:expr,
$extra_feature:expr,
$min_fn:ident, $max_fn:ident,
$align:expr,
}
}
+ doc_comment! {
+ concat!("Get atomic access to a `&mut ", stringify!($int_type), "`.
+
+",
+if_not_8_bit! {
+ $int_type,
+ concat!(
+ "**Note:** This function is only available on targets where `",
+ stringify!($int_type), "` has an alignment of ", $align, " bytes."
+ )
+},
+"
+
+# Examples
+
+```
+#![feature(atomic_from_mut)]
+", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering};
+
+let mut some_int = 123;
+let a = ", stringify!($atomic_type), "::from_mut(&mut some_int);
+a.store(100, Ordering::Relaxed);
+assert_eq!(some_int, 100);
+```
+ "),
+ #[inline]
+ $(#[cfg($from_mut_cfg)])?
+ #[unstable(feature = "atomic_from_mut", issue = "76314")]
+ pub fn from_mut(v: &mut $int_type) -> &Self {
+ let [] = [(); align_of::<Self>() - align_of::<$int_type>()];
+ // SAFETY:
+ // - the mutable reference guarantees unique ownership.
+ // - the alignment of `$int_type` and `Self` is the
+ // same on all platforms enabled by `$from_mut_cfg`
+ // as verified above.
+ unsafe { &*(v as *mut $int_type as *mut Self) }
+ }
+ }
+
doc_comment! {
concat!("Consumes the atomic and returns the contained value.
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ from_mut: cfg(not(target_arch = "x86")),
"i64", "../../../std/primitive.i64.html",
"",
atomic_min, atomic_max,
stable(feature = "integer_atomics_stable", since = "1.34.0"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ from_mut: cfg(not(target_arch = "x86")),
"u64", "../../../std/primitive.u64.html",
"",
atomic_umin, atomic_umax,
unstable(feature = "integer_atomics", issue = "32976"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ from_mut: cfg(not(target_arch = "x86_64")),
"i128", "../../../std/primitive.i128.html",
"#![feature(integer_atomics)]\n\n",
atomic_min, atomic_max,
unstable(feature = "integer_atomics", issue = "32976"),
rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"),
unstable(feature = "integer_atomics", issue = "32976"),
+ from_mut: cfg(not(target_arch = "x86_64")),
"u128", "../../../std/primitive.u128.html",
"#![feature(integer_atomics)]\n\n",
atomic_umin, atomic_umax,
#[stable(feature = "futures_api", since = "1.36.0")]
impl<T> From<T> for Poll<T> {
+ /// Convert to a `Ready` variant.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// # use core::task::Poll;
+ /// assert_eq!(Poll::from(true), Poll::Ready(true));
+ /// ```
fn from(t: T) -> Poll<T> {
Poll::Ready(t)
}
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn from_secs_f64(secs: f64) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn from_secs_f64(secs: f64) -> Duration {
const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
let nanos = secs * (NANOS_PER_SEC as f64);
if !nanos.is_finite() {
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn from_secs_f32(secs: f32) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn from_secs_f32(secs: f32) -> Duration {
const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32;
let nanos = secs * (NANOS_PER_SEC as f32);
if !nanos.is_finite() {
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn mul_f64(self, rhs: f64) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn mul_f64(self, rhs: f64) -> Duration {
Duration::from_secs_f64(rhs * self.as_secs_f64())
}
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn mul_f32(self, rhs: f32) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn mul_f32(self, rhs: f32) -> Duration {
Duration::from_secs_f32(rhs * self.as_secs_f32())
}
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn div_f64(self, rhs: f64) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn div_f64(self, rhs: f64) -> Duration {
Duration::from_secs_f64(self.as_secs_f64() / rhs)
}
/// ```
#[stable(feature = "duration_float", since = "1.38.0")]
#[inline]
- pub fn div_f32(self, rhs: f32) -> Duration {
+ #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")]
+ pub const fn div_f32(self, rhs: f32) -> Duration {
Duration::from_secs_f32(self.as_secs_f32() / rhs)
}
-use core::cmp::{self, Ordering::*};
+use core::cmp::{
+ self,
+ Ordering::{self, *},
+};
#[test]
fn test_int_totalord() {
assert!(SketchyNum { num: 37 } == SketchyNum { num: 34 });
assert!(SketchyNum { num: 25 } != SketchyNum { num: 57 });
}
+
+#[test]
+fn ordering_const() {
+ // test that the methods of `Ordering` are usable in a const context
+
+ const ORDERING: Ordering = Greater;
+
+ const REVERSE: Ordering = ORDERING.reverse();
+ assert_eq!(REVERSE, Less);
+
+ const THEN: Ordering = Equal.then(ORDERING);
+ assert_eq!(THEN, Greater);
+}
#![feature(array_chunks)]
#![feature(array_methods)]
#![feature(array_map)]
+#![feature(array_windows)]
#![feature(bool_to_option)]
#![feature(bound_cloned)]
#![feature(box_syntax)]
#![feature(core_private_diy_float)]
#![feature(debug_non_exhaustive)]
#![feature(dec2flt)]
+#![feature(div_duration)]
+#![feature(duration_consts_2)]
#![feature(duration_constants)]
#![feature(duration_saturating_ops)]
+#![feature(duration_zero)]
#![feature(exact_size_is_empty)]
#![feature(fixed_size_array)]
#![feature(flt2dec)]
int_module!(i32, i32);
+
+#[test]
+fn test_arith_operation() {
+ let a: isize = 10;
+ assert_eq!(a * (a - 1), 90);
+ let i32_a: isize = 10;
+ assert_eq!(i32_a, 10);
+ assert_eq!(i32_a - 10, 0);
+ assert_eq!(i32_a / 10, 1);
+ assert_eq!(i32_a - 20, -10);
+ assert_eq!(i32_a << 10, 10240);
+ assert_eq!(i32_a << 16, 655360);
+ assert_eq!(i32_a * 16, 160);
+ assert_eq!(i32_a * i32_a * i32_a, 1000);
+ assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000);
+ assert_eq!(i32_a * i32_a / i32_a * i32_a, 100);
+ assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640);
+ let i32_b: isize = 0x10101010;
+ assert_eq!(i32_b + 1 - 1, i32_b);
+ assert_eq!(i32_b << 1, i32_b << 1);
+ assert_eq!(i32_b >> 1, i32_b >> 1);
+ assert_eq!(i32_b & i32_b << 1, 0);
+ assert_eq!(i32_b | i32_b << 1, 0x30303030);
+ let i32_c: isize = 0x10101010;
+ assert_eq!(
+ i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3),
+ i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)
+ );
+}
assert_eq!(v1, [13, 14, 19, 20, 4]);
}
+#[test]
+fn test_array_windows_infer() {
+ let v: &[i32] = &[0, 1, 0, 1];
+ assert_eq!(v.array_windows::<2>().count(), 3);
+ let c = v.array_windows();
+ for &[a, b] in c {
+ assert_eq!(a + b, 1);
+ }
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6];
+ let total = v2.array_windows().map(|&[a, b, c]| a + b + c).sum::<i32>();
+ assert_eq!(total, 3 + 6 + 9 + 12 + 15);
+}
+
+#[test]
+fn test_array_windows_count() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let c = v.array_windows::<3>();
+ assert_eq!(c.count(), 4);
+
+ let v2: &[i32] = &[0, 1, 2, 3, 4];
+ let c2 = v2.array_windows::<6>();
+ assert_eq!(c2.count(), 0);
+
+ let v3: &[i32] = &[];
+ let c3 = v3.array_windows::<2>();
+ assert_eq!(c3.count(), 0);
+}
+
+#[test]
+fn test_array_windows_nth() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let snd = v.array_windows::<4>().nth(1);
+ assert_eq!(snd, Some(&[1, 2, 3, 4]));
+ let mut arr_windows = v.array_windows::<2>();
+ assert_ne!(arr_windows.nth(0), arr_windows.nth(0));
+ let last = v.array_windows::<3>().last();
+ assert_eq!(last, Some(&[3, 4, 5]));
+}
+
+#[test]
+fn test_array_windows_nth_back() {
+ let v: &[i32] = &[0, 1, 2, 3, 4, 5];
+ let snd = v.array_windows::<4>().nth_back(1);
+ assert_eq!(snd, Some(&[1, 2, 3, 4]));
+ let mut arr_windows = v.array_windows::<2>();
+ assert_ne!(arr_windows.nth_back(0), arr_windows.nth_back(0));
+}
+
#[test]
fn test_rchunks_count() {
let v: &[i32] = &[0, 1, 2, 3, 4, 5];
assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s");
assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s");
}
+
+#[test]
+fn duration_const() {
+ // test that the methods of `Duration` are usable in a const context
+
+ const DURATION: Duration = Duration::new(0, 123_456_789);
+
+ const SUB_SEC_MILLIS: u32 = DURATION.subsec_millis();
+ assert_eq!(SUB_SEC_MILLIS, 123);
+
+ const SUB_SEC_MICROS: u32 = DURATION.subsec_micros();
+ assert_eq!(SUB_SEC_MICROS, 123_456);
+
+ const SUB_SEC_NANOS: u32 = DURATION.subsec_nanos();
+ assert_eq!(SUB_SEC_NANOS, 123_456_789);
+
+ const ZERO: Duration = Duration::zero();
+ assert_eq!(ZERO, Duration::new(0, 0));
+
+ const IS_ZERO: bool = ZERO.is_zero();
+ assert!(IS_ZERO);
+
+ const ONE: Duration = Duration::new(1, 0);
+
+ const SECONDS: u64 = ONE.as_secs();
+ assert_eq!(SECONDS, 1);
+
+ const FROM_SECONDS: Duration = Duration::from_secs(1);
+ assert_eq!(FROM_SECONDS, ONE);
+
+ const SECONDS_F32: f32 = ONE.as_secs_f32();
+ assert_eq!(SECONDS_F32, 1.0);
+
+ const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0);
+ assert_eq!(FROM_SECONDS_F32, ONE);
+
+ const SECONDS_F64: f64 = ONE.as_secs_f64();
+ assert_eq!(SECONDS_F64, 1.0);
+
+ const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0);
+ assert_eq!(FROM_SECONDS_F64, ONE);
+
+ const MILLIS: u128 = ONE.as_millis();
+ assert_eq!(MILLIS, 1_000);
+
+ const FROM_MILLIS: Duration = Duration::from_millis(1_000);
+ assert_eq!(FROM_MILLIS, ONE);
+
+ const MICROS: u128 = ONE.as_micros();
+ assert_eq!(MICROS, 1_000_000);
+
+ const FROM_MICROS: Duration = Duration::from_micros(1_000_000);
+ assert_eq!(FROM_MICROS, ONE);
+
+ const NANOS: u128 = ONE.as_nanos();
+ assert_eq!(NANOS, 1_000_000_000);
+
+ const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000);
+ assert_eq!(FROM_NANOS, ONE);
+
+ const MAX: Duration = Duration::new(u64::MAX, 999_999_999);
+
+ const CHECKED_ADD: Option<Duration> = MAX.checked_add(ONE);
+ assert_eq!(CHECKED_ADD, None);
+
+ const CHECKED_SUB: Option<Duration> = ZERO.checked_sub(ONE);
+ assert_eq!(CHECKED_SUB, None);
+
+ const CHECKED_MUL: Option<Duration> = ONE.checked_mul(1);
+ assert_eq!(CHECKED_MUL, Some(ONE));
+
+ const MUL_F32: Duration = ONE.mul_f32(1.0);
+ assert_eq!(MUL_F32, ONE);
+
+ const MUL_F64: Duration = ONE.mul_f64(1.0);
+ assert_eq!(MUL_F64, ONE);
+
+ const CHECKED_DIV: Option<Duration> = ONE.checked_div(1);
+ assert_eq!(CHECKED_DIV, Some(ONE));
+
+ const DIV_F32: Duration = ONE.div_f32(1.0);
+ assert_eq!(DIV_F32, ONE);
+
+ const DIV_F64: Duration = ONE.div_f64(1.0);
+ assert_eq!(DIV_F64, ONE);
+
+ const DIV_DURATION_F32: f32 = ONE.div_duration_f32(ONE);
+ assert_eq!(DIV_DURATION_F32, 1.0);
+
+ const DIV_DURATION_F64: f64 = ONE.div_duration_f64(ONE);
+ assert_eq!(DIV_DURATION_F64, 1.0);
+
+ const SATURATING_ADD: Duration = MAX.saturating_add(ONE);
+ assert_eq!(SATURATING_ADD, MAX);
+
+ const SATURATING_SUB: Duration = ZERO.saturating_sub(ONE);
+ assert_eq!(SATURATING_SUB, ZERO);
+
+ const SATURATING_MUL: Duration = MAX.saturating_mul(2);
+ assert_eq!(SATURATING_MUL, MAX);
+}
cell::{Cell, UnsafeCell},
fmt,
marker::PhantomData,
- mem::{self, MaybeUninit},
+ mem::MaybeUninit,
ops::{Deref, Drop},
panic::{RefUnwindSafe, UnwindSafe},
sync::Once,
/// ```
#[unstable(feature = "once_cell", issue = "74465")]
pub fn into_inner(mut self) -> Option<T> {
- // SAFETY: Safe because we immediately free `self` without dropping
- let inner = unsafe { self.take_inner() };
-
- // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set
- // the state to uninitialized.
- mem::forget(self);
- inner
+ self.take()
}
/// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state.
/// ```
#[unstable(feature = "once_cell", issue = "74465")]
pub fn take(&mut self) -> Option<T> {
- mem::take(self).into_inner()
- }
-
- /// Takes the wrapped value out of a `SyncOnceCell`.
- /// Afterwards the cell is no longer initialized.
- ///
- /// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell
- /// are valid. Only used by `into_inner` and `drop`.
- unsafe fn take_inner(&mut self) -> Option<T> {
- // The mutable reference guarantees there are no other threads that can observe us
- // taking out the wrapped value.
- // Right after this function `self` is supposed to be freed, so it makes little sense
- // to atomically set the state to uninitialized.
if self.is_initialized() {
- let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit()));
- Some(value.into_inner().assume_init())
+ self.once = Once::new();
+ // SAFETY: `self.value` is initialized and contains a valid `T`.
+ // `self.once` is reset, so `is_initialized()` will be false again
+ // which prevents the value from being read twice.
+ unsafe { Some((&mut *self.value.get()).assume_init_read()) }
} else {
None
}
unsafe impl<#[may_dangle] T> Drop for SyncOnceCell<T> {
fn drop(&mut self) {
- // SAFETY: The cell is being dropped, so it can't be accessed again.
- // We also don't touch the `T`, which validates our usage of #[may_dangle].
- unsafe { self.take_inner() };
+ if self.is_initialized() {
+ // Safety: The cell is initialized and being dropped, so it can't
+ // be accessed again. We also don't touch the `T` other than
+ // dropping it, which validates our usage of #[may_dangle].
+ unsafe { (&mut *self.value.get()).assume_init_drop() };
+ }
}
}
#![feature(core_intrinsics)]
#![feature(custom_test_frameworks)]
#![feature(decl_macro)]
-#![feature(doc_alias)]
+#![cfg_attr(bootstrap, feature(doc_alias))]
#![feature(doc_cfg)]
#![feature(doc_keyword)]
#![feature(doc_masked)]
//! [`Read`]: io::Read
#![stable(feature = "process", since = "1.0.0")]
+#![deny(unsafe_op_in_unsafe_fn)]
#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))]
mod tests;
#[inline]
unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
+ // SAFETY: Read is guaranteed to work on uninitialized memory
+ unsafe { Initializer::nop() }
}
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
- Initializer::nop()
+ // SAFETY: Read is guaranteed to work on uninitialized memory
+ unsafe { Initializer::nop() }
}
}
impl Once {
/// Creates a new `Once` value.
+ #[inline]
#[stable(feature = "once_new", since = "1.2.0")]
#[rustc_const_stable(feature = "const_once_new", since = "1.32.0")]
pub const fn new() -> Once {
+++ /dev/null
-use crate::ffi::OsString;
-use crate::fmt;
-use crate::hash::{Hash, Hasher};
-use crate::io::{self, IoSlice, IoSliceMut, SeekFrom};
-use crate::path::{Path, PathBuf};
-use crate::sys::time::SystemTime;
-use crate::sys::{unsupported, Void};
-
-pub struct File(Void);
-
-pub struct FileAttr(Void);
-
-pub struct ReadDir(Void);
-
-pub struct DirEntry(Void);
-
-#[derive(Clone, Debug)]
-pub struct OpenOptions {}
-
-pub struct FilePermissions(Void);
-
-pub struct FileType(Void);
-
-#[derive(Debug)]
-pub struct DirBuilder {}
-
-impl FileAttr {
- pub fn size(&self) -> u64 {
- match self.0 {}
- }
-
- pub fn perm(&self) -> FilePermissions {
- match self.0 {}
- }
-
- pub fn file_type(&self) -> FileType {
- match self.0 {}
- }
-
- pub fn modified(&self) -> io::Result<SystemTime> {
- match self.0 {}
- }
-
- pub fn accessed(&self) -> io::Result<SystemTime> {
- match self.0 {}
- }
-
- pub fn created(&self) -> io::Result<SystemTime> {
- match self.0 {}
- }
-}
-
-impl Clone for FileAttr {
- fn clone(&self) -> FileAttr {
- match self.0 {}
- }
-}
-
-impl FilePermissions {
- pub fn readonly(&self) -> bool {
- match self.0 {}
- }
-
- pub fn set_readonly(&mut self, _readonly: bool) {
- match self.0 {}
- }
-}
-
-impl Clone for FilePermissions {
- fn clone(&self) -> FilePermissions {
- match self.0 {}
- }
-}
-
-impl PartialEq for FilePermissions {
- fn eq(&self, _other: &FilePermissions) -> bool {
- match self.0 {}
- }
-}
-
-impl Eq for FilePermissions {}
-
-impl fmt::Debug for FilePermissions {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl FileType {
- pub fn is_dir(&self) -> bool {
- match self.0 {}
- }
-
- pub fn is_file(&self) -> bool {
- match self.0 {}
- }
-
- pub fn is_symlink(&self) -> bool {
- match self.0 {}
- }
-}
-
-impl Clone for FileType {
- fn clone(&self) -> FileType {
- match self.0 {}
- }
-}
-
-impl Copy for FileType {}
-
-impl PartialEq for FileType {
- fn eq(&self, _other: &FileType) -> bool {
- match self.0 {}
- }
-}
-
-impl Eq for FileType {}
-
-impl Hash for FileType {
- fn hash<H: Hasher>(&self, _h: &mut H) {
- match self.0 {}
- }
-}
-
-impl fmt::Debug for FileType {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl fmt::Debug for ReadDir {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl Iterator for ReadDir {
- type Item = io::Result<DirEntry>;
-
- fn next(&mut self) -> Option<io::Result<DirEntry>> {
- match self.0 {}
- }
-}
-
-impl DirEntry {
- pub fn path(&self) -> PathBuf {
- match self.0 {}
- }
-
- pub fn file_name(&self) -> OsString {
- match self.0 {}
- }
-
- pub fn metadata(&self) -> io::Result<FileAttr> {
- match self.0 {}
- }
-
- pub fn file_type(&self) -> io::Result<FileType> {
- match self.0 {}
- }
-}
-
-impl OpenOptions {
- pub fn new() -> OpenOptions {
- OpenOptions {}
- }
-
- pub fn read(&mut self, _read: bool) {}
- pub fn write(&mut self, _write: bool) {}
- pub fn append(&mut self, _append: bool) {}
- pub fn truncate(&mut self, _truncate: bool) {}
- pub fn create(&mut self, _create: bool) {}
- pub fn create_new(&mut self, _create_new: bool) {}
-}
-
-impl File {
- pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
- unsupported()
- }
-
- pub fn file_attr(&self) -> io::Result<FileAttr> {
- match self.0 {}
- }
-
- pub fn fsync(&self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn datasync(&self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn truncate(&self, _size: u64) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_read_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_write_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn flush(&self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
- match self.0 {}
- }
-
- pub fn duplicate(&self) -> io::Result<File> {
- match self.0 {}
- }
-
- pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn diverge(&self) -> ! {
- match self.0 {}
- }
-}
-
-impl DirBuilder {
- pub fn new() -> DirBuilder {
- DirBuilder {}
- }
-
- pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
- unsupported()
- }
-}
-
-impl fmt::Debug for File {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
- unsupported()
-}
-
-pub fn unlink(_p: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
- match perm.0 {}
-}
-
-pub fn rmdir(_p: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
- unsupported()
-}
-
-pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
- unsupported()
-}
-
-pub fn stat(_p: &Path) -> io::Result<FileAttr> {
- unsupported()
-}
-
-pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
- unsupported()
-}
-
-pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
- unsupported()
-}
-
-pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
- unsupported()
-}
+++ /dev/null
-use crate::mem;
-
-#[derive(Copy, Clone)]
-pub struct IoSlice<'a>(&'a [u8]);
-
-impl<'a> IoSlice<'a> {
- #[inline]
- pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
- IoSlice(buf)
- }
-
- #[inline]
- pub fn advance(&mut self, n: usize) {
- self.0 = &self.0[n..]
- }
-
- #[inline]
- pub fn as_slice(&self) -> &[u8] {
- self.0
- }
-}
-
-pub struct IoSliceMut<'a>(&'a mut [u8]);
-
-impl<'a> IoSliceMut<'a> {
- #[inline]
- pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
- IoSliceMut(buf)
- }
-
- #[inline]
- pub fn advance(&mut self, n: usize) {
- let slice = mem::replace(&mut self.0, &mut []);
- let (_, remaining) = slice.split_at_mut(n);
- self.0 = remaining;
- }
-
- #[inline]
- pub fn as_slice(&self) -> &[u8] {
- self.0
- }
-
- #[inline]
- pub fn as_mut_slice(&mut self) -> &mut [u8] {
- self.0
- }
-}
pub mod env;
pub mod ext;
pub mod fd;
+#[path = "../unsupported/fs.rs"]
pub mod fs;
+#[path = "../unsupported/io.rs"]
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod path;
+#[path = "../unsupported/pipe.rs"]
pub mod pipe;
+#[path = "../unsupported/process.rs"]
pub mod process;
pub mod rwlock;
pub mod stack_overflow;
+++ /dev/null
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::sys::Void;
-
-pub struct AnonPipe(Void);
-
-impl AnonPipe {
- pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_read_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_write_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn diverge(&self) -> ! {
- match self.0 {}
- }
-}
-
-pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
- match p1.0 {}
-}
+++ /dev/null
-use crate::ffi::OsStr;
-use crate::fmt;
-use crate::io;
-use crate::sys::fs::File;
-use crate::sys::pipe::AnonPipe;
-use crate::sys::{unsupported, Void};
-use crate::sys_common::process::CommandEnv;
-
-pub use crate::ffi::OsString as EnvKey;
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
- env: CommandEnv,
-}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
- pub stdin: Option<AnonPipe>,
- pub stdout: Option<AnonPipe>,
- pub stderr: Option<AnonPipe>,
-}
-
-pub enum Stdio {
- Inherit,
- Null,
- MakePipe,
-}
-
-impl Command {
- pub fn new(_program: &OsStr) -> Command {
- Command { env: Default::default() }
- }
-
- pub fn arg(&mut self, _arg: &OsStr) {}
-
- pub fn env_mut(&mut self) -> &mut CommandEnv {
- &mut self.env
- }
-
- pub fn cwd(&mut self, _dir: &OsStr) {}
-
- pub fn stdin(&mut self, _stdin: Stdio) {}
-
- pub fn stdout(&mut self, _stdout: Stdio) {}
-
- pub fn stderr(&mut self, _stderr: Stdio) {}
-
- pub fn spawn(
- &mut self,
- _default: Stdio,
- _needs_stdin: bool,
- ) -> io::Result<(Process, StdioPipes)> {
- unsupported()
- }
-}
-
-impl From<AnonPipe> for Stdio {
- fn from(pipe: AnonPipe) -> Stdio {
- pipe.diverge()
- }
-}
-
-impl From<File> for Stdio {
- fn from(file: File) -> Stdio {
- file.diverge()
- }
-}
-
-impl fmt::Debug for Command {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Ok(())
- }
-}
-
-pub struct ExitStatus(Void);
-
-impl ExitStatus {
- pub fn success(&self) -> bool {
- match self.0 {}
- }
-
- pub fn code(&self) -> Option<i32> {
- match self.0 {}
- }
-}
-
-impl Clone for ExitStatus {
- fn clone(&self) -> ExitStatus {
- match self.0 {}
- }
-}
-
-impl Copy for ExitStatus {}
-
-impl PartialEq for ExitStatus {
- fn eq(&self, _other: &ExitStatus) -> bool {
- match self.0 {}
- }
-}
-
-impl Eq for ExitStatus {}
-
-impl fmt::Debug for ExitStatus {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl fmt::Display for ExitStatus {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(bool);
-
-impl ExitCode {
- pub const SUCCESS: ExitCode = ExitCode(false);
- pub const FAILURE: ExitCode = ExitCode(true);
-
- pub fn as_i32(&self) -> i32 {
- self.0 as i32
- }
-}
-
-pub struct Process(Void);
-
-impl Process {
- pub fn id(&self) -> u32 {
- match self.0 {}
- }
-
- pub fn kill(&mut self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn wait(&mut self) -> io::Result<ExitStatus> {
- match self.0 {}
- }
-
- pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
- match self.0 {}
- }
-}
use super::*;
-use crate::mem::{self, MaybeUninit};
-use core::array::FixedSizeArray;
-// Verify that the bytes of initialized RWLock are the same as in
-// libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to
-// be changed too.
+// Verify that the byte pattern libunwind uses to initialize an RWLock is
+// equivalent to the value of RWLock::new(). If the value changes,
+// `src/UnwindRustSgx.h` in libunwind needs to be changed too.
#[test]
fn test_c_rwlock_initializer() {
#[rustfmt::skip]
- const RWLOCK_INIT: &[u8] = &[
+ const C_RWLOCK_INIT: &[u8] = &[
/* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
/* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
];
- #[inline(never)]
- fn zero_stack() {
- test::black_box(MaybeUninit::<[RWLock; 16]>::zeroed());
- }
-
- #[inline(never)]
- unsafe fn rwlock_new(init: &mut MaybeUninit<RWLock>) {
- init.write(RWLock::new());
- }
+ // For the test to work, we need the padding/unused bytes in RWLock to be
+ // initialized as 0. In practice, this is the case with statics.
+ static RUST_RWLOCK_INIT: RWLock = RWLock::new();
unsafe {
- // try hard to make sure that the padding/unused bytes in RWLock
- // get initialized as 0. If the assertion below fails, that might
- // just be an issue with the test code and not with the value of
- // RWLOCK_INIT.
- zero_stack();
- let mut init = MaybeUninit::<RWLock>::zeroed();
- rwlock_new(&mut init);
- assert_eq!(mem::transmute::<_, [u8; 144]>(init.assume_init()).as_slice(), RWLOCK_INIT)
+ // If the assertion fails, that not necessarily an issue with the value
+ // of C_RWLOCK_INIT. It might just be an issue with the way padding
+ // bytes are initialized in the test code.
+ assert_eq!(&crate::mem::transmute_copy::<_, [u8; 144]>(&RUST_RWLOCK_INIT), C_RWLOCK_INIT);
};
}
}
}
-#[cfg(any(
- target_os = "android",
- target_os = "illumos",
- target_os = "redox",
- target_os = "solaris"
-))]
-#[inline]
-unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
- // On android we currently target API level 9 which unfortunately
- // doesn't have the `posix_memalign` API used below. Instead we use
- // `memalign`, but this unfortunately has the property on some systems
- // where the memory returned cannot be deallocated by `free`!
- //
- // Upon closer inspection, however, this appears to work just fine with
- // Android, so for this platform we should be fine to call `memalign`
- // (which is present in API level 9). Some helpful references could
- // possibly be chromium using memalign [1], attempts at documenting that
- // memalign + free is ok [2] [3], or the current source of chromium
- // which still uses memalign on android [4].
- //
- // [1]: https://codereview.chromium.org/10796020/
- // [2]: https://code.google.com/p/android/issues/detail?id=35391
- // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
- // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
- // /memory/aligned_memory.cc
- libc::memalign(layout.align(), layout.size()) as *mut u8
-}
-
-#[cfg(not(any(
- target_os = "android",
- target_os = "illumos",
- target_os = "redox",
- target_os = "solaris"
-)))]
-#[inline]
-unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
- let mut out = ptr::null_mut();
- // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
- // Since these are all powers of 2, we can just use max.
- let align = layout.align().max(crate::mem::size_of::<usize>());
- let ret = libc::posix_memalign(&mut out, align, layout.size());
- if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
+cfg_if::cfg_if! {
+ if #[cfg(any(
+ target_os = "android",
+ target_os = "illumos",
+ target_os = "redox",
+ target_os = "solaris"
+ ))] {
+ #[inline]
+ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ // On android we currently target API level 9 which unfortunately
+ // doesn't have the `posix_memalign` API used below. Instead we use
+ // `memalign`, but this unfortunately has the property on some systems
+ // where the memory returned cannot be deallocated by `free`!
+ //
+ // Upon closer inspection, however, this appears to work just fine with
+ // Android, so for this platform we should be fine to call `memalign`
+ // (which is present in API level 9). Some helpful references could
+ // possibly be chromium using memalign [1], attempts at documenting that
+ // memalign + free is ok [2] [3], or the current source of chromium
+ // which still uses memalign on android [4].
+ //
+ // [1]: https://codereview.chromium.org/10796020/
+ // [2]: https://code.google.com/p/android/issues/detail?id=35391
+ // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
+ // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
+ // /memory/aligned_memory.cc
+ libc::memalign(layout.align(), layout.size()) as *mut u8
+ }
+ } else if #[cfg(target_os = "wasi")] {
+ #[inline]
+ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ libc::aligned_alloc(layout.align(), layout.size()) as *mut u8
+ }
+ } else {
+ #[inline]
+ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
+ let mut out = ptr::null_mut();
+ // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
+ // Since these are all powers of 2, we can just use max.
+ let align = layout.align().max(crate::mem::size_of::<usize>());
+ let ret = libc::posix_memalign(&mut out, align, layout.size());
+ if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
+ }
+ }
}
///
/// The `dst` path will be a symbolic link pointing to the `src` path.
///
-/// # Note
-///
-/// On Windows, you must specify whether a symbolic link points to a file
-/// or directory. Use `os::windows::fs::symlink_file` to create a
-/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
-/// symbolic link to a directory. Additionally, the process must have
-/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
-/// symbolic link.
-///
/// # Examples
///
/// ```no_run
pub mod raw;
pub mod thread;
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "openbsd"
+))]
+pub mod ucred;
+
/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
use crate::sys_common::{self, AsInner, FromInner, IntoInner};
use crate::time::Duration;
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "openbsd"
+))]
+use crate::os::unix::ucred;
+
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "openbsd"
+))]
+pub use ucred::UCred;
+
#[cfg(any(
target_os = "linux",
target_os = "android",
SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) })
}
+ /// Gets the peer credentials for this Unix domain socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(peer_credentials_unix_socket)]
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let socket = UnixStream::connect("/tmp/sock")?;
+ /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials");
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+ #[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "openbsd"
+ ))]
+ pub fn peer_cred(&self) -> io::Result<UCred> {
+ ucred::peer_cred(self)
+ }
+
/// Sets the read timeout for the socket.
///
/// If the provided value is [`None`], then [`read`] calls will block
--- /dev/null
+//! Unix peer credentials.
+
+// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on
+// GitHub.
+//
+// For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13
+// Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work.
+
+use libc::{gid_t, pid_t, uid_t};
+
+/// Credentials for a UNIX process for credentials passing.
+#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")]
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+pub struct UCred {
+ /// The UID part of the peer credential. This is the effective UID of the process at the domain
+ /// socket's endpoint.
+ pub uid: uid_t,
+ /// The GID part of the peer credential. This is the effective GID of the process at the domain
+ /// socket's endpoint.
+ pub gid: gid_t,
+ /// The PID part of the peer credential. This field is optional because the PID part of the
+ /// peer credentials is not supported on every platform. On platforms where the mechanism to
+ /// discover the PID exists, this field will be populated to the PID of the process at the
+ /// domain socket's endpoint. Otherwise, it will be set to None.
+ pub pid: Option<pid_t>,
+}
+
+#[cfg(any(target_os = "android", target_os = "linux"))]
+pub use self::impl_linux::peer_cred;
+
+#[cfg(any(
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "openbsd"
+))]
+pub use self::impl_bsd::peer_cred;
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub mod impl_linux {
+ use super::UCred;
+ use crate::os::unix::io::AsRawFd;
+ use crate::os::unix::net::UnixStream;
+ use crate::{io, mem};
+ use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED};
+
+ pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+ let ucred_size = mem::size_of::<ucred>();
+
+ // Trivial sanity checks.
+ assert!(mem::size_of::<u32>() <= mem::size_of::<usize>());
+ assert!(ucred_size <= u32::MAX as usize);
+
+ let mut ucred_size = ucred_size as socklen_t;
+ let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 };
+
+ unsafe {
+ let ret = getsockopt(
+ socket.as_raw_fd(),
+ SOL_SOCKET,
+ SO_PEERCRED,
+ &mut ucred as *mut ucred as *mut c_void,
+ &mut ucred_size,
+ );
+
+ if ret == 0 && ucred_size as usize == mem::size_of::<ucred>() {
+ Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) })
+ } else {
+ Err(io::Error::last_os_error())
+ }
+ }
+ }
+}
+
+#[cfg(any(
+ target_os = "dragonfly",
+ target_os = "macos",
+ target_os = "ios",
+ target_os = "freebsd",
+ target_os = "openbsd"
+))]
+pub mod impl_bsd {
+ use super::UCred;
+ use crate::io;
+ use crate::os::unix::io::AsRawFd;
+ use crate::os::unix::net::UnixStream;
+
+ pub fn peer_cred(socket: &UnixStream) -> io::Result<UCred> {
+ let mut cred = UCred { uid: 1, gid: 1, pid: None };
+ unsafe {
+ let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid);
+
+ if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) }
+ }
+ }
+}
--- /dev/null
+use crate::os::unix::net::UnixStream;
+use libc::{getegid, geteuid};
+
+#[test]
+#[cfg(any(
+ target_os = "android",
+ target_os = "linux",
+ target_os = "dragonfly",
+ target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "openbsd"
+))]
+fn test_socket_pair() {
+ // Create two connected sockets and get their peer credentials. They should be equal.
+ let (sock_a, sock_b) = UnixStream::pair().unwrap();
+ let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap());
+ assert_eq!(cred_a, cred_b);
+
+ // Check that the UID and GIDs match up.
+ let uid = unsafe { geteuid() };
+ let gid = unsafe { getegid() };
+ assert_eq!(cred_a.uid, uid);
+ assert_eq!(cred_a.gid, gid);
+}
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
match self.0 {}
}
-
- pub fn diverge(&self) -> ! {
- match self.0 {}
- }
}
impl DirBuilder {
pub mod mutex;
pub mod net;
pub mod os;
+#[path = "../unix/path.rs"]
pub mod path;
pub mod pipe;
pub mod process;
+++ /dev/null
-use crate::ffi::OsStr;
-use crate::path::Prefix;
-
-#[inline]
-pub fn is_sep_byte(b: u8) -> bool {
- b == b'/'
-}
-
-#[inline]
-pub fn is_verbatim_sep(b: u8) -> bool {
- b == b'/'
-}
-
-pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
- None
-}
-
-pub const MAIN_SEP_STR: &str = "/";
-pub const MAIN_SEP: char = '/';
}
impl From<File> for Stdio {
- fn from(file: File) -> Stdio {
- file.diverge()
+ fn from(_file: File) -> Stdio {
+ panic!("unsupported")
}
}
///
/// The `dst` path will be a symbolic link pointing to the `src` path.
///
-/// # Note
-///
-/// On Windows, you must specify whether a symbolic link points to a file
-/// or directory. Use `os::windows::fs::symlink_file` to create a
-/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
-/// symbolic link to a directory. Additionally, the process must have
-/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
-/// symbolic link.
-///
/// # Examples
///
/// ```no_run
+++ /dev/null
-#![deny(unsafe_op_in_unsafe_fn)]
-
-use crate::alloc::{GlobalAlloc, Layout, System};
-use crate::ptr;
-use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN};
-
-// SAFETY: All methods implemented follow the contract rules defined
-// in `GlobalAlloc`.
-#[stable(feature = "alloc_system_type", since = "1.28.0")]
-unsafe impl GlobalAlloc for System {
- #[inline]
- unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
- if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
- // SAFETY: `libc::malloc` is guaranteed to be safe, it will allocate
- // `layout.size()` bytes of memory and return a pointer to it
- unsafe { libc::malloc(layout.size()) as *mut u8 }
- } else {
- // SAFETY: `libc::aligned_alloc` is guaranteed to be safe if
- // `layout.size()` is a multiple of `layout.align()`. This
- // constraint can be satisfied if `pad_to_align` is called,
- // which creates a layout by rounding the size of this layout up
- // to a multiple of the layout's alignment
- let aligned_layout = layout.pad_to_align();
- unsafe { libc::aligned_alloc(aligned_layout.align(), aligned_layout.size()) as *mut u8 }
- }
- }
-
- #[inline]
- unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
- if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
- // SAFETY: `libc::calloc` is safe as long that `layout.size() * 1`
- // would not result in integer overflow which cannot happen,
- // multiplying by one never overflows
- unsafe { libc::calloc(layout.size(), 1) as *mut u8 }
- } else {
- // SAFETY: The safety contract for `alloc` must be upheld by the caller
- let ptr = unsafe { self.alloc(layout.clone()) };
- if !ptr.is_null() {
- // SAFETY: in the case of the `ptr` being not null
- // it will be properly aligned and a valid ptr
- // which satisfies `ptr::write_bytes` safety constrains
- unsafe { ptr::write_bytes(ptr, 0, layout.size()) };
- }
- ptr
- }
- }
-
- #[inline]
- unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
- // SAFETY: `libc::free` is guaranteed to be safe if `ptr` is allocated
- // by this allocator or if `ptr` is NULL
- unsafe { libc::free(ptr as *mut libc::c_void) }
- }
-
- #[inline]
- unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
- if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
- // SAFETY: `libc::realloc` is safe if `ptr` is allocated by this
- // allocator or NULL
- // - If `new_size` is 0 and `ptr` is not NULL, it will act as `libc::free`
- // - If `new_size` is not 0 and `ptr` is NULL, it will act as `libc::malloc`
- // - Else, it will resize the block accordingly
- unsafe { libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 }
- } else {
- // SAFETY: The safety contract for `realloc_fallback` must be upheld by the caller
- unsafe { realloc_fallback(self, ptr, layout, new_size) }
- }
- }
-}
use crate::io as std_io;
use crate::mem;
+#[path = "../unix/alloc.rs"]
pub mod alloc;
pub mod args;
#[path = "../unsupported/cmath.rs"]
pub mod os;
pub use crate::sys_common::os_str_bytes as os_str;
pub mod ext;
+#[path = "../unix/path.rs"]
pub mod path;
+#[path = "../unsupported/pipe.rs"]
pub mod pipe;
+#[path = "../unsupported/process.rs"]
pub mod process;
#[path = "../unsupported/rwlock.rs"]
pub mod rwlock;
+++ /dev/null
-use crate::ffi::OsStr;
-use crate::path::Prefix;
-
-#[inline]
-pub fn is_sep_byte(b: u8) -> bool {
- b == b'/'
-}
-
-#[inline]
-pub fn is_verbatim_sep(b: u8) -> bool {
- b == b'/'
-}
-
-pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
- None
-}
-
-pub const MAIN_SEP_STR: &str = "/";
-pub const MAIN_SEP: char = '/';
+++ /dev/null
-#![deny(unsafe_op_in_unsafe_fn)]
-
-use crate::io::{self, IoSlice, IoSliceMut};
-use crate::sys::Void;
-
-pub struct AnonPipe(Void);
-
-impl AnonPipe {
- pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_read_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- match self.0 {}
- }
-
- pub fn is_write_vectored(&self) -> bool {
- match self.0 {}
- }
-
- pub fn diverge(&self) -> ! {
- match self.0 {}
- }
-}
-
-pub fn read2(p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
- match p1.0 {}
-}
+++ /dev/null
-#![deny(unsafe_op_in_unsafe_fn)]
-
-use crate::ffi::OsStr;
-use crate::fmt;
-use crate::io;
-use crate::sys::fs::File;
-use crate::sys::pipe::AnonPipe;
-use crate::sys::{unsupported, Void};
-use crate::sys_common::process::CommandEnv;
-
-pub use crate::ffi::OsString as EnvKey;
-
-////////////////////////////////////////////////////////////////////////////////
-// Command
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct Command {
- env: CommandEnv,
-}
-
-// passed back to std::process with the pipes connected to the child, if any
-// were requested
-pub struct StdioPipes {
- pub stdin: Option<AnonPipe>,
- pub stdout: Option<AnonPipe>,
- pub stderr: Option<AnonPipe>,
-}
-
-pub enum Stdio {
- Inherit,
- Null,
- MakePipe,
-}
-
-impl Command {
- pub fn new(_program: &OsStr) -> Command {
- Command { env: Default::default() }
- }
-
- pub fn arg(&mut self, _arg: &OsStr) {}
-
- pub fn env_mut(&mut self) -> &mut CommandEnv {
- &mut self.env
- }
-
- pub fn cwd(&mut self, _dir: &OsStr) {}
-
- pub fn stdin(&mut self, _stdin: Stdio) {}
-
- pub fn stdout(&mut self, _stdout: Stdio) {}
-
- pub fn stderr(&mut self, _stderr: Stdio) {}
-
- pub fn spawn(
- &mut self,
- _default: Stdio,
- _needs_stdin: bool,
- ) -> io::Result<(Process, StdioPipes)> {
- unsupported()
- }
-}
-
-impl From<AnonPipe> for Stdio {
- fn from(pipe: AnonPipe) -> Stdio {
- pipe.diverge()
- }
-}
-
-impl From<File> for Stdio {
- fn from(_file: File) -> Stdio {
- panic!("unsupported")
- }
-}
-
-impl fmt::Debug for Command {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Ok(())
- }
-}
-
-pub struct ExitStatus(Void);
-
-impl ExitStatus {
- pub fn success(&self) -> bool {
- match self.0 {}
- }
-
- pub fn code(&self) -> Option<i32> {
- match self.0 {}
- }
-}
-
-impl Clone for ExitStatus {
- fn clone(&self) -> ExitStatus {
- match self.0 {}
- }
-}
-
-impl Copy for ExitStatus {}
-
-impl PartialEq for ExitStatus {
- fn eq(&self, _other: &ExitStatus) -> bool {
- match self.0 {}
- }
-}
-
-impl Eq for ExitStatus {}
-
-impl fmt::Debug for ExitStatus {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-impl fmt::Display for ExitStatus {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self.0 {}
- }
-}
-
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
-pub struct ExitCode(bool);
-
-impl ExitCode {
- pub const SUCCESS: ExitCode = ExitCode(false);
- pub const FAILURE: ExitCode = ExitCode(true);
-
- pub fn as_i32(&self) -> i32 {
- self.0 as i32
- }
-}
-
-pub struct Process(Void);
-
-impl Process {
- pub fn id(&self) -> u32 {
- match self.0 {}
- }
-
- pub fn kill(&mut self) -> io::Result<()> {
- match self.0 {}
- }
-
- pub fn wait(&mut self) -> io::Result<ExitStatus> {
- match self.0 {}
- }
-
- pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
- match self.0 {}
- }
-}
pub mod net;
#[path = "../unsupported/os.rs"]
pub mod os;
-#[path = "../unsupported/path.rs"]
+#[path = "../unix/path.rs"]
pub mod path;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
// thread_local's, or it is being recursively initialized.
//
// Macos: Inlining this function can cause two `tlv_get_addr` calls to
- // be performed for every call to `Key::get`. The #[cold] hint makes
- // that less likely.
+ // be performed for every call to `Key::get`.
// LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722
- #[cold]
+ #[inline(never)]
unsafe fn try_initialize<F: FnOnce() -> T>(&self, init: F) -> Option<&'static T> {
if !mem::needs_drop::<T>() || self.try_register_dtor() {
Some(self.inner.initialize(init))
-Subproject commit 78891cdf292c23278ca8723bd543100249159604
+Subproject commit 718175b34a39e4e3d59b40e35930326edc515b87
```
# build the whole compiler
- ./x.py build
+ ./x.py build --stage 2
# build the stage1 compiler
- ./x.py build --stage 1
+ ./x.py build
# build stage0 libstd
./x.py build --stage 0 library/std
that belong to stage n or earlier:
```
- # keep old build products for stage 0 and build stage 1
- ./x.py build --keep-stage 0 --stage 1
+ # build stage 1, keeping old build products for stage 0
+ ./x.py build --keep-stage 0
```
* `test` - a command for executing unit tests. Like the `build` command this
## Incremental builds
-You can configure rustbuild to use incremental compilation. Because
-incremental is new and evolving rapidly, if you want to use it, it is
-recommended that you replace the snapshot with a locally installed
-nightly build of rustc. You will want to keep this up to date.
-
-To follow this course of action, first thing you will want to do is to
-install a nightly, presumably using `rustup`. You will then want to
-configure your directory to use this build, like so:
-
-```sh
-# configure to use local rust instead of downloading a beta.
-# `--local-rust-root` is optional here. If elided, we will
-# use whatever rustc we find on your PATH.
-$ ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild
-```
-
-After that, you can use the `--incremental` flag to actually do
-incremental builds:
+You can configure rustbuild to use incremental compilation with the
+`--incremental` flag:
```sh
$ ./x.py build --incremental
in `build/<host>/stage0-incremental`. Note that we only use incremental
compilation for the stage0 -> stage1 compilation -- this is because
the stage1 compiler is changing, and we don't try to cache and reuse
-incremental artifacts across different versions of the compiler. For
-this reason, `--incremental` defaults to `--stage 1` (though you can
-manually select a higher stage, if you prefer).
+incremental artifacts across different versions of the compiler.
You can always drop the `--incremental` to build as normal (but you
will still be using the local nightly as your bootstrap).
`Config` struct.
* Adding a sanity check? Take a look at `bootstrap/sanity.rs`.
-If you have any questions feel free to reach out on `#infra` channel in the
-[Rust Discord server][rust-discord] or ask on internals.rust-lang.org. When
+If you have any questions feel free to reach out on the `#t-infra` channel in
+the [Rust Zulip server][rust-zulip] or ask on internals.rust-lang.org. When
you encounter bugs, please file issues on the rust-lang/rust issue tracker.
-[rust-discord]: https://discord.gg/rust-lang
+[rust-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra
llvm_assertions = self.get_toml('assertions', 'llvm') == 'true'
if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)):
self._download_ci_llvm(llvm_sha, llvm_assertions)
+ for binary in ["llvm-config", "FileCheck"]:
+ self.fix_bin_or_dylib("{}/bin/{}".format(self.llvm_root(), binary))
with output(self.llvm_stamp()) as llvm_stamp:
llvm_stamp.write(self.date + llvm_sha + str(llvm_assertions))
}
fn new_internal(build: &Build, kind: Kind, paths: Vec<PathBuf>) -> Builder<'_> {
- let top_stage = if let Some(explicit_stage) = build.config.stage {
- explicit_stage
- } else {
- // See https://github.com/rust-lang/compiler-team/issues/326
- match kind {
- Kind::Doc => 0,
- Kind::Build | Kind::Test => 1,
- Kind::Bench | Kind::Dist | Kind::Install => 2,
- // These are all bootstrap tools, which don't depend on the compiler.
- // The stage we pass shouldn't matter, but use 0 just in case.
- Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => 0,
- }
- };
-
Builder {
build,
- top_stage,
+ top_stage: build.config.stage,
kind,
cache: Cache::new(),
stack: RefCell::new(Vec::new()),
Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(),
};
- let this = Self::new_internal(build, kind, paths.to_owned());
-
- // CI should always run stage 2 builds, unless it specifically states otherwise
- #[cfg(not(test))]
- if build.config.stage.is_none() && build.ci_env != crate::CiEnv::None {
- match kind {
- Kind::Test | Kind::Doc | Kind::Build | Kind::Bench | Kind::Dist | Kind::Install => {
- assert_eq!(this.top_stage, 2)
- }
- Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => {}
- }
- }
-
- this
+ Self::new_internal(build, kind, paths.to_owned())
}
pub fn execute_cli(&self) {
/// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic
/// library lookup path.
- pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Cargo) {
+ pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) {
// Windows doesn't need dylib path munging because the dlls for the
// compiler live next to the compiler and the system will find them
// automatically.
return;
}
- add_dylib_path(vec![self.rustc_libdir(compiler)], &mut cmd.command);
+ add_dylib_path(vec![self.rustc_libdir(compiler)], cmd);
}
/// Gets a path to the compiler specified.
self.command.env(key.as_ref(), value.as_ref());
self
}
+
+ pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) {
+ builder.add_rustc_lib_path(compiler, &mut self.command);
+ }
}
impl From<Cargo> for Command {
use crate::config::{Config, TargetSelection};
use std::thread;
-fn configure(host: &[&str], target: &[&str]) -> Config {
- let mut config = Config::default_opts();
+fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
+ let mut config = Config::parse(&[cmd.to_owned()]);
// don't save toolstates
config.save_toolstates = None;
config.skip_only_host_steps = false;
#[test]
fn build_default() {
- let build = Build::new(configure(&[], &[]));
+ let build = Build::new(configure("build", &[], &[]));
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
#[test]
fn build_stage_0() {
- let config = Config { stage: Some(0), ..configure(&[], &[]) };
+ let config = Config { stage: 0, ..configure("build", &[], &[]) };
let build = Build::new(config);
let mut builder = Builder::new(&build);
builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]);
#[test]
fn doc_default() {
- let mut config = configure(&[], &[]);
+ let mut config = configure("doc", &[], &[]);
config.compiler_docs = true;
config.cmd = Subcommand::Doc { paths: Vec::new(), open: false };
let build = Build::new(config);
use pretty_assertions::assert_eq;
fn configure(host: &[&str], target: &[&str]) -> Config {
- Config { stage: Some(2), ..super::configure(host, target) }
+ Config { stage: 2, ..super::configure("dist", host, target) }
}
#[test]
#[test]
fn test_with_no_doc_stage0() {
let mut config = configure(&[], &[]);
- config.stage = Some(0);
+ config.stage = 0;
config.cmd = Subcommand::Test {
paths: vec!["library/std".into()],
test_args: vec![],
use std::fmt;
use std::fs;
use std::path::{Path, PathBuf};
-use std::process;
use crate::cache::{Interned, INTERNER};
use crate::flags::Flags;
pub skip_only_host_steps: bool,
pub on_fail: Option<String>,
- pub stage: Option<u32>,
+ pub stage: u32,
pub keep_stage: Vec<u32>,
pub src: PathBuf,
pub jobs: Option<u32>,
configure_args: Option<Vec<String>>,
local_rebuild: Option<bool>,
print_step_timings: Option<bool>,
+ doc_stage: Option<u32>,
+ build_stage: Option<u32>,
+ test_stage: Option<u32>,
+ install_stage: Option<u32>,
+ dist_stage: Option<u32>,
+ bench_stage: Option<u32>,
}
/// TOML representation of various global install decisions.
pub fn parse(args: &[String]) -> Config {
let flags = Flags::parse(&args);
- let file = flags.config.clone();
let mut config = Config::default_opts();
config.exclude = flags.exclude;
config.rustc_error_format = flags.rustc_error_format;
config.json_output = flags.json_output;
config.on_fail = flags.on_fail;
- config.stage = flags.stage;
config.jobs = flags.jobs.map(threads_from_config);
config.cmd = flags.cmd;
config.incremental = flags.incremental;
config.out = dir;
}
- let toml = file
+ #[cfg(test)]
+ let toml = TomlConfig::default();
+ #[cfg(not(test))]
+ let toml = flags
+ .config
.map(|file| {
+ use std::process;
+
let contents = t!(fs::read_to_string(&file));
match toml::from_str(&contents) {
Ok(table) => table,
})
.unwrap_or_else(TomlConfig::default);
- let build = toml.build.clone().unwrap_or_default();
+ let build = toml.build.unwrap_or_default();
// If --target was specified but --host wasn't specified, don't run any host-only tests.
let has_hosts = build.host.is_some() || flags.host.is_some();
set(&mut config.configure_args, build.configure_args);
set(&mut config.local_rebuild, build.local_rebuild);
set(&mut config.print_step_timings, build.print_step_timings);
+
+ // See https://github.com/rust-lang/compiler-team/issues/326
+ config.stage = match config.cmd {
+ Subcommand::Doc { .. } => flags.stage.or(build.doc_stage).unwrap_or(0),
+ Subcommand::Build { .. } => flags.stage.or(build.build_stage).unwrap_or(1),
+ Subcommand::Test { .. } => flags.stage.or(build.test_stage).unwrap_or(1),
+ Subcommand::Bench { .. } => flags.stage.or(build.bench_stage).unwrap_or(2),
+ Subcommand::Dist { .. } => flags.stage.or(build.dist_stage).unwrap_or(2),
+ Subcommand::Install { .. } => flags.stage.or(build.install_stage).unwrap_or(2),
+ // These are all bootstrap tools, which don't depend on the compiler.
+ // The stage we pass shouldn't matter, but use 0 just in case.
+ Subcommand::Clean { .. }
+ | Subcommand::Check { .. }
+ | Subcommand::Clippy { .. }
+ | Subcommand::Fix { .. }
+ | Subcommand::Run { .. }
+ | Subcommand::Format { .. } => flags.stage.unwrap_or(0),
+ };
+
+ // CI should always run stage 2 builds, unless it specifically states otherwise
+ #[cfg(not(test))]
+ if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None {
+ match config.cmd {
+ Subcommand::Test { .. }
+ | Subcommand::Doc { .. }
+ | Subcommand::Build { .. }
+ | Subcommand::Bench { .. }
+ | Subcommand::Dist { .. }
+ | Subcommand::Install { .. } => assert_eq!(config.stage, 2),
+ Subcommand::Clean { .. }
+ | Subcommand::Check { .. }
+ | Subcommand::Clippy { .. }
+ | Subcommand::Fix { .. }
+ | Subcommand::Run { .. }
+ | Subcommand::Format { .. } => {}
+ }
+ }
+
config.verbose = cmp::max(config.verbose, flags.verbose);
if let Some(ref install) = toml.install {
Nomicon, "src/doc/nomicon", "nomicon";
Reference, "src/doc/reference", "reference";
RustByExample, "src/doc/rust-by-example", "rust-by-example";
- RustcBook, "src/doc/rustc", "rustc";
RustdocBook, "src/doc/rustdoc", "rustdoc";
);
symlink_dir(config, src, dst)
}
+
+#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct RustcBook {
+ pub compiler: Compiler,
+ pub target: TargetSelection,
+}
+
+impl Step for RustcBook {
+ type Output = ();
+ const DEFAULT: bool = true;
+ const ONLY_HOSTS: bool = true;
+
+ fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+ let builder = run.builder;
+ run.path("src/doc/rustc").default_condition(builder.config.docs)
+ }
+
+ fn make_run(run: RunConfig<'_>) {
+ run.builder.ensure(RustcBook {
+ compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+ target: run.target,
+ });
+ }
+
+ /// Builds the rustc book.
+ ///
+ /// The lints are auto-generated by a tool, and then merged into the book
+ /// in the "md-doc" directory in the build output directory. Then
+ /// "rustbook" is used to convert it to HTML.
+ fn run(self, builder: &Builder<'_>) {
+ let out_base = builder.md_doc_out(self.target).join("rustc");
+ t!(fs::create_dir_all(&out_base));
+ let out_listing = out_base.join("src/lints");
+ builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base);
+ builder.info(&format!("Generating lint docs ({})", self.target));
+ let rustc = builder.rustc(self.compiler);
+ // The tool runs `rustc` for extracting output examples, so it needs a
+ // functional sysroot.
+ builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
+ let mut cmd = builder.tool_cmd(Tool::LintDocs);
+ cmd.arg("--src");
+ cmd.arg(builder.src.join("compiler"));
+ cmd.arg("--out");
+ cmd.arg(&out_listing);
+ cmd.arg("--rustc");
+ cmd.arg(rustc);
+ if builder.config.verbose() {
+ cmd.arg("--verbose");
+ }
+ // If the lib directories are in an unusual location (changed in
+ // config.toml), then this needs to explicitly update the dylib search
+ // path.
+ builder.add_rustc_lib_path(self.compiler, &mut cmd);
+ builder.run(&mut cmd);
+ // Run rustbook/mdbook to generate the HTML pages.
+ builder.ensure(RustbookSrc {
+ target: self.target,
+ name: INTERNER.intern_str("rustc"),
+ src: INTERNER.intern_path(out_base),
+ });
+ if is_explicit_request(builder, "src/doc/rustc") {
+ let out = builder.doc_out(self.target);
+ let index = out.join("rustc").join("index.html");
+ open(builder, &index);
+ }
+ }
+}
Err(m) => m,
};
+ if builder.config.llvm_link_shared && target.contains("windows") {
+ panic!("shared linking to LLVM is not currently supported on Windows");
+ }
+
builder.info(&format!("Building LLVM for {}", target));
t!(stamp.remove());
let _time = util::timeit(&builder);
&[],
);
- builder.add_rustc_lib_path(compiler, &mut cargo);
+ cargo.add_rustc_lib_path(builder, compiler);
cargo.arg("--").args(builder.config.cmd.test_args());
if try_run(builder, &mut cargo.into()) {
t!(fs::create_dir_all(&dir));
cargo.env("RUSTFMT_TEST_DIR", dir);
- builder.add_rustc_lib_path(compiler, &mut cargo);
+ cargo.add_rustc_lib_path(builder, compiler);
if try_run(builder, &mut cargo.into()) {
builder.save_toolstate("rustfmt", ToolState::TestPass);
cargo.arg("--").args(builder.config.cmd.test_args());
- builder.add_rustc_lib_path(compiler, &mut cargo);
+ cargo.add_rustc_lib_path(builder, compiler);
if !try_run(builder, &mut cargo.into()) {
return;
cargo.arg("--").args(builder.config.cmd.test_args());
- builder.add_rustc_lib_path(compiler, &mut cargo);
+ cargo.add_rustc_lib_path(builder, compiler);
builder.run(&mut cargo.into());
}
RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true;
RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes";
ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors";
+ LintDocs, "src/tools/lint-docs", "lint-docs";
);
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf -
-
-cd git-2.10.0
-make configure
-hide_output ./configure --prefix=/rustroot
-hide_output make -j10
-hide_output make install
-
-cd ..
-rm -rf git-2.10.0
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x
-
-cd linux-3.2.84
-hide_output make mrproper
-hide_output make INSTALL_HDR_PATH=dest headers_install
-
-find dest/include \( -name .install -o -name ..install.cmd \) -delete
-yes | cp -fr dest/include/* /usr/include
-
-cd ..
-rm -rf linux-3.2.84
+++ /dev/null
-#!/usr/bin/env bash
-
-set -ex
-source shared.sh
-
-curl https://www.cpan.org/src/5.0/perl-5.28.0.tar.gz | \
- tar xzf -
-
-cd perl-5.28.0
-
-# Gotta do some hackery to tell python about our custom OpenSSL build, but other
-# than that fairly normal.
-CC=gcc \
-CFLAGS='-I /rustroot/include -fgnu89-inline' \
-LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \
- hide_output ./configure.gnu
-hide_output make -j10
-hide_output make install
-
-cd ..
-rm -rf perl-5.28.0
uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master
with:
github_token: "${{ secrets.github_token }}"
- # TODO: remove the condition on RUST_CI_TEMP_SKIP_CANCEL_OUTDATED once
- # we remove the `auto-fallible` job.
- if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' && !env.RUST_CI_TEMP_SKIP_CANCEL_OUTDATED
+ if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'
<<: *step
- name: collect CPU statistics
DEPLOY_TOOLSTATES_JSON: toolstates-linux.json
<<: *job-linux-xl
+ ####################
+ # macOS Builders #
+ ####################
+
+ - name: dist-x86_64-apple
+ env:
+ SCRIPT: ./x.py dist
+ RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ DIST_REQUIRE_ALL_TOOLS: 1
+ <<: *job-macos-xl
+
+ - name: dist-x86_64-apple-alt
+ env:
+ SCRIPT: ./x.py dist
+ RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ <<: *job-macos-xl
+
+ - name: x86_64-apple
+ env:
+ SCRIPT: ./x.py --stage 2 test
+ RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.8
+ MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ <<: *job-macos-xl
+
+ ####################
+ # macOS Builders #
+ ####################
+
+ - name: dist-x86_64-apple
+ env:
+ SCRIPT: ./x.py dist
+ RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ DIST_REQUIRE_ALL_TOOLS: 1
+ <<: *job-macos-xl
+
+ - name: dist-x86_64-apple-alt
+ env:
+ SCRIPT: ./x.py dist
+ RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ <<: *job-macos-xl
+
+ - name: x86_64-apple
+ env:
+ SCRIPT: ./x.py --stage 2 test
+ RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+ RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+ MACOSX_DEPLOYMENT_TARGET: 10.8
+ MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+ NO_LLVM_ASSERTIONS: 1
+ NO_DEBUG_ASSERTIONS: 1
+ <<: *job-macos-xl
+
######################
# Windows Builders #
######################
- name: aarch64-gnu
<<: *job-aarch64-linux
- ####################
- # macOS Builders #
- ####################
-
- - name: dist-x86_64-apple
- env:
- SCRIPT: ./x.py dist
- RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
- DIST_REQUIRE_ALL_TOOLS: 1
-
- # TODO: remove once we move this job away from auto-fallible.
- # Also, remove the variable from the cancel-outdated-builds step
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- <<: *job-macos-xl
-
- - name: dist-x86_64-apple-alt
- env:
- SCRIPT: ./x.py dist
- RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
-
- # TODO: remove once we move this job away from auto-fallible.
- # Also, remove the variable from the cancel-outdated-builds step
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- <<: *job-macos-xl
-
- - name: x86_64-apple
- env:
- SCRIPT: ./x.py --stage 2 test
- RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
- RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
- MACOSX_DEPLOYMENT_TARGET: 10.8
- MACOSX_STD_DEPLOYMENT_TARGET: 10.7
- NO_LLVM_ASSERTIONS: 1
- NO_DEBUG_ASSERTIONS: 1
-
- # TODO: remove once we move this job away from auto-fallible.
- # Also, remove the variable from the cancel-outdated-builds step
- RUST_CI_TEMP_SKIP_CANCEL_OUTDATED: 1
- <<: *job-macos-xl
-
master:
name: master
runs-on: ubuntu-latest
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1"
+ # If we're distributing binaries, we want a shared LLVM link. We're already
+ # going to link LLVM to the LLVM tools dynamically, so we need to ship a
+ # libLLVM library anyway.
+ if !isWindows; then
+ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set llvm.link-shared=true"
+ fi
+
if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
elif [ "$DEPLOY_ALT" != "" ]; then
Here's a list of each lint group, and the lints that they are made up of:
-| group | description | lints |
-|---------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| nonstandard-style | Violation of standard naming conventions | non-camel-case-types, non-snake-case, non-upper-case-globals |
-| warnings | all lints that would be issuing warnings | all lints that would be issuing warnings |
-| edition-2018 | Lints that will be turned into errors in Rust 2018 | tyvar-behind-raw-pointer |
-| rust-2018-idioms | Lints to nudge you toward idiomatic features of Rust 2018 | bare-trait-object, unreachable-pub |
-| unused | These lints detect things being declared but not used | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens |
-| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, tyvar-behind-raw-pointer, unstable-name-collision |
+{{groups-table}}
Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`.
This is the `unused_variables` lint, and it tells you that you've introduced
a variable that you don't use in your code. That's not *wrong*, so it's not
an error, but it might be a bug, so you get a warning.
+
+## Future-incompatible lints
+
+Sometimes the compiler needs to be changed to fix an issue that can cause
+existing code to stop compiling. "Future-incompatible" lints are issued in
+these cases to give users of Rust a smooth transition to the new behavior.
+Initially, the compiler will continue to accept the problematic code and issue
+a warning. The warning has a description of the problem, a notice that this
+will become an error in the future, and a link to a tracking issue that
+provides detailed information and an opportunity for feedback. This gives
+users some time to fix the code to accommodate the change. After some time,
+the warning may become an error.
+
+The following is an example of what a future-incompatible looks like:
+
+```text
+warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133)
+ --> lint_example.rs:11:13
+ |
+11 | let y = &x.data.0;
+ | ^^^^^^^^^
+ |
+ = note: `#[warn(safe_packed_borrows)]` on by default
+ = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+ = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
+ = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
+```
+
+For more information about the process and policy of future-incompatible
+changes, see [RFC 1589].
+
+[RFC 1589]: https://github.com/rust-lang/rfcs/blob/master/text/1589-rustc-bug-fix-procedure.md
# Allowed-by-default lints
-These lints are all set to the 'allow' level by default. As such, they won't show up
-unless you set them to a higher lint level with a flag or attribute.
-
-## anonymous-parameters
-
-This lint detects anonymous parameters. Some example code that triggers this lint:
-
-```rust
-trait Foo {
- fn foo(usize);
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: use of deprecated anonymous parameter
- --> src/lib.rs:5:11
- |
-5 | fn foo(usize);
- | ^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
-```
-
-This syntax is mostly a historical accident, and can be worked around quite
-easily:
-
-```rust
-trait Foo {
- fn foo(_: usize);
-}
-```
-
-## bare-trait-object
-
-This lint suggests using `dyn Trait` for trait objects. Some example code
-that triggers this lint:
-
-```rust
-#![feature(dyn_trait)]
-
-trait Trait { }
-
-fn takes_trait_object(_: Box<Trait>) {
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: trait objects without an explicit `dyn` are deprecated
- --> src/lib.rs:7:30
- |
-7 | fn takes_trait_object(_: Box<Trait>) {
- | ^^^^^ help: use `dyn`: `dyn Trait`
- |
-```
-
-To fix it, do as the help message suggests:
-
-```rust
-#![feature(dyn_trait)]
-#![deny(bare_trait_objects)]
-
-trait Trait { }
-
-fn takes_trait_object(_: Box<dyn Trait>) {
-}
-```
-
-## box-pointers
-
-This lints use of the Box type. Some example code that triggers this lint:
-
-```rust
-struct Foo {
- x: Box<isize>,
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: type uses owned (Box type) pointers: std::boxed::Box<isize>
- --> src/lib.rs:6:5
- |
-6 | x: Box<isize> //~ ERROR type uses owned
- | ^^^^^^^^^^^^^
- |
-```
-
-This lint is mostly historical, and not particularly useful. `Box<T>` used to
-be built into the language, and the only way to do heap allocation. Today's
-Rust can call into other allocators, etc.
-
-## elided-lifetime-in-path
-
-This lint detects the use of hidden lifetime parameters. Some example code
-that triggers this lint:
-
-```rust
-struct Foo<'a> {
- x: &'a u32
-}
-
-fn foo(x: &Foo) {
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: hidden lifetime parameters are deprecated, try `Foo<'_>`
- --> src/lib.rs:5:12
- |
-5 | fn foo(x: &Foo) {
- | ^^^
- |
-```
-
-Lifetime elision elides this lifetime, but that is being deprecated.
-
-## missing-copy-implementations
-
-This lint detects potentially-forgotten implementations of `Copy`. Some
-example code that triggers this lint:
-
-```rust
-pub struct Foo {
- pub field: i32
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: type could implement `Copy`; consider adding `impl Copy`
- --> src/main.rs:3:1
- |
-3 | / pub struct Foo { //~ ERROR type could implement `Copy`; consider adding `impl Copy`
-4 | | pub field: i32
-5 | | }
- | |_^
- |
-```
-
-You can fix the lint by deriving `Copy`.
-
-This lint is set to 'allow' because this code isn't bad; it's common to write
-newtypes like this specifically so that a `Copy` type is no longer `Copy`.
-
-## missing-debug-implementations
-
-This lint detects missing implementations of `fmt::Debug`. Some example code
-that triggers this lint:
-
-```rust
-pub struct Foo;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
- --> src/main.rs:3:1
- |
-3 | pub struct Foo;
- | ^^^^^^^^^^^^^^^
- |
-```
-
-You can fix the lint by deriving `Debug`.
-
-## missing-docs
-
-This lint detects missing documentation for public items. Some example code
-that triggers this lint:
-
-```rust
-pub fn foo() {}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: missing documentation for crate
- --> src/main.rs:1:1
- |
-1 | / #![deny(missing_docs)]
-2 | |
-3 | | pub fn foo() {}
-4 | |
-5 | | fn main() {}
- | |____________^
- |
-
-error: missing documentation for a function
- --> src/main.rs:3:1
- |
-3 | pub fn foo() {}
- | ^^^^^^^^^^^^
-
-```
-
-To fix the lint, add documentation to all items.
-
-## single-use-lifetimes
-
-This lint detects lifetimes that are only used once. Some example code that
-triggers this lint:
-
-```rust
-struct Foo<'x> {
- x: &'x u32
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: lifetime name `'x` only used once
- --> src/main.rs:3:12
- |
-3 | struct Foo<'x> {
- | ^^
- |
-```
-
-## trivial-casts
-
-This lint detects trivial casts which could be replaced with coercion, which may require
-type ascription or a temporary variable. Some example code
-that triggers this lint:
-
-```rust
-let x: &u32 = &42;
-let _ = x as *const u32;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: trivial cast: `&u32` as `*const u32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
- --> src/main.rs:5:13
- |
-5 | let _ = x as *const u32;
- | ^^^^^^^^^^^^^^^
- |
-note: lint level defined here
- --> src/main.rs:1:9
- |
-1 | #![deny(trivial_casts)]
- | ^^^^^^^^^^^^^
-```
-
-## trivial-numeric-casts
-
-This lint detects trivial casts of numeric types which could be removed. Some
-example code that triggers this lint:
-
-```rust
-let x = 42i32 as i32;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: trivial numeric cast: `i32` as `i32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
- --> src/main.rs:4:13
- |
-4 | let x = 42i32 as i32;
- | ^^^^^^^^^^^^
- |
-```
-
-## unreachable-pub
-
-This lint triggers for `pub` items not reachable from the crate root. Some
-example code that triggers this lint:
-
-```rust
-mod foo {
- pub mod bar {
-
- }
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unreachable `pub` item
- --> src/main.rs:4:5
- |
-4 | pub mod bar {
- | ---^^^^^^^^
- | |
- | help: consider restricting its visibility: `pub(crate)`
- |
-```
-
-## unsafe-code
-
-This lint catches usage of `unsafe` code. Some example code that triggers this lint:
-
-```rust
-fn main() {
- unsafe {
-
- }
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: usage of an `unsafe` block
- --> src/main.rs:4:5
- |
-4 | / unsafe {
-5 | |
-6 | | }
- | |_____^
- |
-```
-
-## unstable-features
-
-This lint is deprecated and no longer used.
-
-## unused-extern-crates
-
-This lint guards against `extern crate` items that are never used. Some
-example code that triggers this lint:
-
-```rust,ignore
-extern crate semver;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unused extern crate
- --> src/main.rs:3:1
- |
-3 | extern crate semver;
- | ^^^^^^^^^^^^^^^^^^^^
- |
-```
-
-## unused-import-braces
-
-This lint catches unnecessary braces around an imported item. Some example
-code that triggers this lint:
-
-```rust
-use test::{A};
-
-pub mod test {
- pub struct A;
-}
-# fn main() {}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: braces around A is unnecessary
- --> src/main.rs:3:1
- |
-3 | use test::{A};
- | ^^^^^^^^^^^^^^
- |
-```
-
-To fix it, `use test::A;`
-
-## unused-qualifications
-
-This lint detects unnecessarily qualified names. Some example code that triggers this lint:
-
-```rust
-mod foo {
- pub fn bar() {}
-}
-
-fn main() {
- use foo::bar;
- foo::bar();
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unnecessary qualification
- --> src/main.rs:9:5
- |
-9 | foo::bar();
- | ^^^^^^^^
- |
-```
-
-You can call `bar()` directly, without the `foo::`.
-
-## unused-results
-
-This lint checks for the unused result of an expression in a statement. Some
-example code that triggers this lint:
-
-```rust,no_run
-fn foo<T>() -> T { panic!() }
-
-fn main() {
- foo::<usize>();
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unused result
- --> src/main.rs:6:5
- |
-6 | foo::<usize>();
- | ^^^^^^^^^^^^^^^
- |
-```
-
-## variant-size-differences
-
-This lint detects enums with widely varying variant sizes. Some example code that triggers this lint:
-
-```rust
-enum En {
- V0(u8),
- VBig([u8; 1024]),
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: enum variant is more than three times larger (1024 bytes) than the next largest
- --> src/main.rs:5:5
- |
-5 | VBig([u8; 1024]), //~ ERROR variant is more than three times larger
- | ^^^^^^^^^^^^^^^^
- |
-```
+This file is auto-generated by the lint-docs script.
# Deny-by-default lints
-These lints are all set to the 'deny' level by default.
-
-## exceeding-bitshifts
-
-This lint detects that a shift exceeds the type's number of bits. Some
-example code that triggers this lint:
-
-```rust,ignore
-1_i32 << 32;
-```
-
-This will produce:
-
-```text
-error: bitshift exceeds the type's number of bits
- --> src/main.rs:2:5
- |
-2 | 1_i32 << 32;
- | ^^^^^^^^^^^
- |
-```
-
-## invalid-type-param-default
-
-This lint detects type parameter default erroneously allowed in invalid location. Some
-example code that triggers this lint:
-
-```rust,ignore
-fn foo<T=i32>(t: T) {}
-```
-
-This will produce:
-
-```text
-error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions.
- --> src/main.rs:4:8
- |
-4 | fn foo<T=i32>(t: T) {}
- | ^
- |
- = note: `#[deny(invalid_type_param_default)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-```
-
-## mutable-transmutes
-
-This lint catches transmuting from `&T` to `&mut T` because it is undefined
-behavior. Some example code that triggers this lint:
-
-```rust,ignore
-unsafe {
- let y = std::mem::transmute::<&i32, &mut i32>(&5);
-}
-```
-
-This will produce:
-
-```text
-error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell
- --> src/main.rs:3:17
- |
-3 | let y = std::mem::transmute::<&i32, &mut i32>(&5);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-```
-
-
-## no-mangle-const-items
-
-This lint detects any `const` items with the `#[no_mangle]` attribute.
-Constants do not have their symbols exported, and therefore, this probably
-means you meant to use a `static`, not a `const`. Some example code that
-triggers this lint:
-
-```rust,ignore
-#[no_mangle]
-const FOO: i32 = 5;
-```
-
-This will produce:
-
-```text
-error: const items should never be `#[no_mangle]`
- --> src/main.rs:3:1
- |
-3 | const FOO: i32 = 5;
- | -----^^^^^^^^^^^^^^
- | |
- | help: try a static value: `pub static`
- |
-```
-
-## overflowing-literals
-
-This lint detects literal out of range for its type. Some
-example code that triggers this lint:
-
-```rust,compile_fail
-let x: u8 = 1000;
-```
-
-This will produce:
-
-```text
-error: literal out of range for u8
- --> src/main.rs:2:17
- |
-2 | let x: u8 = 1000;
- | ^^^^
- |
-```
-
-## patterns-in-fns-without-body
-
-This lint detects patterns in functions without body were that were
-previously erroneously allowed. Some example code that triggers this lint:
-
-```rust,compile_fail
-trait Trait {
- fn foo(mut arg: u8);
-}
-```
-
-This will produce:
-
-```text
-warning: patterns aren't allowed in methods without bodies
- --> src/main.rs:2:12
- |
-2 | fn foo(mut arg: u8);
- | ^^^^^^^
- |
- = note: `#[warn(patterns_in_fns_without_body)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #35203 <https://github.com/rust-lang/rust/issues/35203>
-```
-
-To fix this, remove the pattern; it can be used in the implementation without
-being used in the definition. That is:
-
-```rust
-trait Trait {
- fn foo(arg: u8);
-}
-
-impl Trait for i32 {
- fn foo(mut arg: u8) {
-
- }
-}
-```
-
-## pub-use-of-private-extern-crate
-
-This lint detects a specific situation of re-exporting a private `extern crate`;
-
-## unknown-crate-types
-
-This lint detects an unknown crate type found in a `#[crate_type]` directive. Some
-example code that triggers this lint:
-
-```rust,ignore
-#![crate_type="lol"]
-```
-
-This will produce:
-
-```text
-error: invalid `crate_type` value
- --> src/lib.rs:1:1
- |
-1 | #![crate_type="lol"]
- | ^^^^^^^^^^^^^^^^^^^^
- |
-```
-
-## const-err
-
-This lint detects expressions that will always panic at runtime and would be an
-error in a `const` context.
-
-```rust,ignore
-let _ = [0; 4][4];
-```
-
-This will produce:
-
-```text
-error: index out of bounds: the len is 4 but the index is 4
- --> src/lib.rs:1:9
- |
-1 | let _ = [0; 4][4];
- | ^^^^^^^^^
- |
-```
-
-## order-dependent-trait-objects
-
-This lint detects a trait coherency violation that would allow creating two
-trait impls for the same dynamic trait object involving marker traits.
+This file is auto-generated by the lint-docs script.
# Warn-by-default lints
-These lints are all set to the 'warn' level by default.
-
-## const-err
-
-This lint detects an erroneous expression while doing constant evaluation. Some
-example code that triggers this lint:
-
-```rust,ignore
-let b = 200u8 + 200u8;
-```
-
-This will produce:
-
-```text
-warning: attempt to add with overflow
- --> src/main.rs:2:9
- |
-2 | let b = 200u8 + 200u8;
- | ^^^^^^^^^^^^^
- |
-```
-
-## dead-code
-
-This lint detects unused, unexported items. Some
-example code that triggers this lint:
-
-```rust
-fn foo() {}
-```
-
-This will produce:
-
-```text
-warning: function is never used: `foo`
- --> src/lib.rs:2:1
- |
-2 | fn foo() {}
- | ^^^^^^^^
- |
-```
-
-## deprecated
-
-This lint detects use of deprecated items. Some
-example code that triggers this lint:
-
-```rust
-#[deprecated]
-fn foo() {}
-
-fn bar() {
- foo();
-}
-```
-
-This will produce:
-
-```text
-warning: use of deprecated item 'foo'
- --> src/lib.rs:7:5
- |
-7 | foo();
- | ^^^
- |
-```
-
-## illegal-floating-point-literal-pattern
-
-This lint detects floating-point literals used in patterns. Some example code
-that triggers this lint:
-
-```rust
-let x = 42.0;
-
-match x {
- 5.0 => {},
- _ => {},
-}
-```
-
-This will produce:
-
-```text
-warning: floating-point literals cannot be used in patterns
- --> src/main.rs:4:9
- |
-4 | 5.0 => {},
- | ^^^
- |
- = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-```
-
-## improper-ctypes
-
-This lint detects proper use of libc types in foreign modules. Some
-example code that triggers this lint:
-
-```rust
-extern "C" {
- static STATIC: String;
-}
-```
-
-This will produce:
-
-```text
-warning: found struct without foreign-function-safe representation annotation in foreign module, consider adding a `#[repr(C)]` attribute to the type
- --> src/main.rs:2:20
- |
-2 | static STATIC: String;
- | ^^^^^^
- |
-```
-
-## late-bound-lifetime-arguments
-
-This lint detects generic lifetime arguments in path segments with
-late bound lifetime parameters. Some example code that triggers this lint:
-
-```rust
-struct S;
-
-impl S {
- fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
-}
-
-fn main() {
- S.late::<'static>(&0, &0);
-}
-```
-
-This will produce:
-
-```text
-warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
- --> src/main.rs:8:14
- |
-4 | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
- | -- the late bound lifetime parameter is introduced here
-...
-8 | S.late::<'static>(&0, &0);
- | ^^^^^^^
- |
- = note: `#[warn(late_bound_lifetime_arguments)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
-```
-
-## non-camel-case-types
-
-This lint detects types, variants, traits and type parameters that don't have
-camel case names. Some example code that triggers this lint:
-
-```rust
-struct s;
-```
-
-This will produce:
-
-```text
-warning: type `s` should have a camel case name such as `S`
- --> src/main.rs:1:1
- |
-1 | struct s;
- | ^^^^^^^^^
- |
-```
-
-## non-shorthand-field-patterns
-
-This lint detects using `Struct { x: x }` instead of `Struct { x }` in a pattern. Some
-example code that triggers this lint:
-
-```rust
-struct Point {
- x: i32,
- y: i32,
-}
-
-
-fn main() {
- let p = Point {
- x: 5,
- y: 5,
- };
-
- match p {
- Point { x: x, y: y } => (),
- }
-}
-```
-
-This will produce:
-
-```text
-warning: the `x:` in this pattern is redundant
- --> src/main.rs:14:17
- |
-14 | Point { x: x, y: y } => (),
- | --^^
- | |
- | help: remove this
- |
-
-warning: the `y:` in this pattern is redundant
- --> src/main.rs:14:23
- |
-14 | Point { x: x, y: y } => (),
- | --^^
- | |
- | help: remove this
-
-```
-
-## non-snake-case
-
-This lint detects variables, methods, functions, lifetime parameters and
-modules that don't have snake case names. Some example code that triggers
-this lint:
-
-```rust
-let X = 5;
-```
-
-This will produce:
-
-```text
-warning: variable `X` should have a snake case name such as `x`
- --> src/main.rs:2:9
- |
-2 | let X = 5;
- | ^
- |
-```
-
-## non-upper-case-globals
-
-This lint detects static constants that don't have uppercase identifiers.
-Some example code that triggers this lint:
-
-```rust
-static x: i32 = 5;
-```
-
-This will produce:
-
-```text
-warning: static variable `x` should have an upper case name such as `X`
- --> src/main.rs:1:1
- |
-1 | static x: i32 = 5;
- | ^^^^^^^^^^^^^^^^^^
- |
-```
-
-## no-mangle-generic-items
-
-This lint detects generic items must be mangled. Some
-example code that triggers this lint:
-
-```rust
-#[no_mangle]
-fn foo<T>(t: T) {
-
-}
-```
-
-This will produce:
-
-```text
-warning: functions generic over types must be mangled
- --> src/main.rs:2:1
- |
-1 | #[no_mangle]
- | ------------ help: remove this attribute
-2 | / fn foo<T>(t: T) {
-3 | |
-4 | | }
- | |_^
- |
-```
-
-## path-statements
-
-This lint detects path statements with no effect. Some example code that
-triggers this lint:
-
-```rust
-let x = 42;
-
-x;
-```
-
-This will produce:
-
-```text
-warning: path statement with no effect
- --> src/main.rs:3:5
- |
-3 | x;
- | ^^
- |
-```
-
-## private-in-public
-
-This lint detects private items in public interfaces not caught by the old implementation. Some
-example code that triggers this lint:
-
-```rust,ignore
-pub trait Trait {
- type A;
-}
-
-pub struct S;
-
-mod foo {
- struct Z;
-
- impl ::Trait for ::S {
- type A = Z;
- }
-}
-# fn main() {}
-```
-
-This will produce:
-
-```text
-error[E0446]: private type `foo::Z` in public interface
- --> src/main.rs:11:9
- |
-11 | type A = Z;
- | ^^^^^^^^^^^ can't leak private type
-```
-
-## private-no-mangle-fns
-
-This lint detects functions marked `#[no_mangle]` that are also private.
-Given that private functions aren't exposed publicly, and `#[no_mangle]`
-controls the public symbol, this combination is erroneous. Some example code
-that triggers this lint:
-
-```rust
-#[no_mangle]
-fn foo() {}
-```
-
-This will produce:
-
-```text
-warning: function is marked `#[no_mangle]`, but not exported
- --> src/main.rs:2:1
- |
-2 | fn foo() {}
- | -^^^^^^^^^^
- | |
- | help: try making it public: `pub`
- |
-```
-
-To fix this, either make it public or remove the `#[no_mangle]`.
-
-## private-no-mangle-statics
-
-This lint detects any statics marked `#[no_mangle]` that are private.
-Given that private statics aren't exposed publicly, and `#[no_mangle]`
-controls the public symbol, this combination is erroneous. Some example code
-that triggers this lint:
-
-```rust
-#[no_mangle]
-static X: i32 = 4;
-```
-
-This will produce:
-
-```text
-warning: static is marked `#[no_mangle]`, but not exported
- --> src/main.rs:2:1
- |
-2 | static X: i32 = 4;
- | -^^^^^^^^^^^^^^^^^
- | |
- | help: try making it public: `pub`
- |
-```
-
-To fix this, either make it public or remove the `#[no_mangle]`.
-
-## renamed-and-removed-lints
-
-This lint detects lints that have been renamed or removed. Some
-example code that triggers this lint:
-
-```rust
-#![deny(raw_pointer_derive)]
-```
-
-This will produce:
-
-```text
-warning: lint raw_pointer_derive has been removed: using derive with raw pointers is ok
- --> src/main.rs:1:9
- |
-1 | #![deny(raw_pointer_derive)]
- | ^^^^^^^^^^^^^^^^^^
- |
-```
-
-To fix this, either remove the lint or use the new name.
-
-## safe-packed-borrows
-
-This lint detects borrowing a field in the interior of a packed structure
-with alignment other than 1. Some example code that triggers this lint:
-
-```rust
-#[repr(packed)]
-pub struct Unaligned<T>(pub T);
-
-pub struct Foo {
- start: u8,
- data: Unaligned<u32>,
-}
-
-fn main() {
- let x = Foo { start: 0, data: Unaligned(1) };
- let y = &x.data.0;
-}
-```
-
-This will produce:
-
-```text
-warning: borrow of packed field requires unsafe function or block (error E0133)
- --> src/main.rs:11:13
- |
-11 | let y = &x.data.0;
- | ^^^^^^^^^
- |
- = note: `#[warn(safe_packed_borrows)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
-```
-
-## stable-features
-
-This lint detects a `#[feature]` attribute that's since been made stable. Some
-example code that triggers this lint:
-
-```rust
-#![feature(test_accepted_feature)]
-```
-
-This will produce:
-
-```text
-warning: this feature has been stable since 1.0.0. Attribute no longer needed
- --> src/main.rs:1:12
- |
-1 | #![feature(test_accepted_feature)]
- | ^^^^^^^^^^^^^^^^^^^^^
- |
-```
-
-To fix, simply remove the `#![feature]` attribute, as it's no longer needed.
-
-## type-alias-bounds
-
-This lint detects bounds in type aliases. These are not currently enforced.
-Some example code that triggers this lint:
-
-```rust
-#[allow(dead_code)]
-type SendVec<T: Send> = Vec<T>;
-```
-
-This will produce:
-
-```text
-warning: bounds on generic parameters are not enforced in type aliases
- --> src/lib.rs:2:17
- |
-2 | type SendVec<T: Send> = Vec<T>;
- | ^^^^
- |
- = note: `#[warn(type_alias_bounds)]` on by default
- = help: the bound will not be checked when the type alias is used, and should be removed
-```
-
-## tyvar-behind-raw-pointer
-
-This lint detects raw pointer to an inference variable. Some
-example code that triggers this lint:
-
-```rust
-let data = std::ptr::null();
-let _ = &data as *const *const ();
-
-if data.is_null() {}
-```
-
-This will produce:
-
-```text
-warning: type annotations needed
- --> src/main.rs:4:13
- |
-4 | if data.is_null() {}
- | ^^^^^^^
- |
- = note: `#[warn(tyvar_behind_raw_pointer)]` on by default
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
- = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>
-```
-
-## unconditional-recursion
-
-This lint detects functions that cannot return without calling themselves.
-Some example code that triggers this lint:
-
-```rust
-fn foo() {
- foo();
-}
-```
-
-This will produce:
-
-```text
-warning: function cannot return without recursing
- --> src/main.rs:1:1
- |
-1 | fn foo() {
- | ^^^^^^^^ cannot return without recursing
-2 | foo();
- | ----- recursive call site
- |
-```
-
-## unknown-lints
-
-This lint detects unrecognized lint attribute. Some
-example code that triggers this lint:
-
-```rust,ignore
-#[allow(not_a_real_lint)]
-```
-
-This will produce:
-
-```text
-warning: unknown lint: `not_a_real_lint`
- --> src/main.rs:1:10
- |
-1 | #![allow(not_a_real_lint)]
- | ^^^^^^^^^^^^^^^
- |
-```
-
-## unreachable-code
-
-This lint detects unreachable code paths. Some example code that
-triggers this lint:
-
-```rust,no_run
-panic!("we never go past here!");
-
-let x = 5;
-```
-
-This will produce:
-
-```text
-warning: unreachable statement
- --> src/main.rs:4:5
- |
-4 | let x = 5;
- | ^^^^^^^^^^
- |
-```
-
-## unreachable-patterns
-
-This lint detects unreachable patterns. Some
-example code that triggers this lint:
-
-```rust
-let x = 5;
-match x {
- y => (),
- 5 => (),
-}
-```
-
-This will produce:
-
-```text
-warning: unreachable pattern
- --> src/main.rs:5:5
- |
-5 | 5 => (),
- | ^
- |
-```
-
-The `y` pattern will always match, so the five is impossible to reach.
-Remember, match arms match in order, you probably wanted to put the `5` case
-above the `y` case.
-
-## unstable-name-collision
-
-This lint detects that you've used a name that the standard library plans to
-add in the future, which means that your code may fail to compile without
-additional type annotations in the future. Either rename, or add those
-annotations now.
-
-## unused-allocation
-
-This lint detects unnecessary allocations that can be eliminated.
-
-## unused-assignments
-
-This lint detects assignments that will never be read. Some
-example code that triggers this lint:
-
-```rust
-let mut x = 5;
-x = 6;
-```
-
-This will produce:
-
-```text
-warning: value assigned to `x` is never read
- --> src/main.rs:4:5
- |
-4 | x = 6;
- | ^
- |
-```
-
-## unused-attributes
-
-This lint detects attributes that were not used by the compiler. Some
-example code that triggers this lint:
-
-```rust
-#![macro_export]
-```
-
-This will produce:
-
-```text
-warning: unused attribute
- --> src/main.rs:1:1
- |
-1 | #![macro_export]
- | ^^^^^^^^^^^^^^^^
- |
-```
-
-## unused-comparisons
-
-This lint detects comparisons made useless by limits of the types involved. Some
-example code that triggers this lint:
-
-```rust
-fn foo(x: u8) {
- x >= 0;
-}
-```
-
-This will produce:
-
-```text
-warning: comparison is useless due to type limits
- --> src/main.rs:6:5
- |
-6 | x >= 0;
- | ^^^^^^
- |
-```
-
-## unused-doc-comment
-
-This lint detects doc comments that aren't used by rustdoc. Some
-example code that triggers this lint:
-
-```rust
-/// docs for x
-let x = 12;
-```
-
-This will produce:
-
-```text
-warning: doc comment not used by rustdoc
- --> src/main.rs:2:5
- |
-2 | /// docs for x
- | ^^^^^^^^^^^^^^
- |
-```
-
-## unused-features
-
-This lint detects unused or unknown features found in crate-level `#[feature]` directives.
-To fix this, simply remove the feature flag.
-
-## unused-imports
-
-This lint detects imports that are never used. Some
-example code that triggers this lint:
-
-```rust
-use std::collections::HashMap;
-```
-
-This will produce:
-
-```text
-warning: unused import: `std::collections::HashMap`
- --> src/main.rs:1:5
- |
-1 | use std::collections::HashMap;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-```
-
-## unused-macros
-
-This lint detects macros that were not used. Some example code that
-triggers this lint:
-
-```rust
-macro_rules! unused {
- () => {};
-}
-
-fn main() {
-}
-```
-
-This will produce:
-
-```text
-warning: unused macro definition
- --> src/main.rs:1:1
- |
-1 | / macro_rules! unused {
-2 | | () => {};
-3 | | }
- | |_^
- |
-```
-
-## unused-must-use
-
-This lint detects unused result of a type flagged as `#[must_use]`. Some
-example code that triggers this lint:
-
-```rust
-fn returns_result() -> Result<(), ()> {
- Ok(())
-}
-
-fn main() {
- returns_result();
-}
-```
-
-This will produce:
-
-```text
-warning: unused `std::result::Result` that must be used
- --> src/main.rs:6:5
- |
-6 | returns_result();
- | ^^^^^^^^^^^^^^^^^
- |
-```
-
-## unused-mut
-
-This lint detects mut variables which don't need to be mutable. Some
-example code that triggers this lint:
-
-```rust
-let mut x = 5;
-```
-
-This will produce:
-
-```text
-warning: variable does not need to be mutable
- --> src/main.rs:2:9
- |
-2 | let mut x = 5;
- | ----^
- | |
- | help: remove this `mut`
- |
-```
-
-## unused-parens
-
-This lint detects `if`, `match`, `while` and `return` with parentheses; they
-do not need them. Some example code that triggers this lint:
-
-```rust
-if(true) {}
-```
-
-This will produce:
-
-```text
-warning: unnecessary parentheses around `if` condition
- --> src/main.rs:2:7
- |
-2 | if(true) {}
- | ^^^^^^ help: remove these parentheses
- |
-```
-
-## unused-unsafe
-
-This lint detects unnecessary use of an `unsafe` block. Some
-example code that triggers this lint:
-
-```rust
-unsafe {}
-```
-
-This will produce:
-
-```text
-warning: unnecessary `unsafe` block
- --> src/main.rs:2:5
- |
-2 | unsafe {}
- | ^^^^^^ unnecessary `unsafe` block
- |
-```
-
-## unused-variables
-
-This lint detects variables which are not used in any way. Some
-example code that triggers this lint:
-
-```rust
-let x = 5;
-```
-
-This will produce:
-
-```text
-warning: unused variable: `x`
- --> src/main.rs:2:9
- |
-2 | let x = 5;
- | ^ help: consider using `_x` instead
- |
-```
-
-## warnings
-
-This lint is a bit special; by changing its level, you change every other warning
-that would produce a warning to whatever value you'd like:
-
-```rust
-#![deny(warnings)]
-```
-
-As such, you won't ever trigger this lint in your code directly.
-
-## while-true
-
-This lint detects `while true { }`. Some example code that triggers this
-lint:
-
-```rust,no_run
-while true {
-
-}
-```
-
-This will produce:
-
-```text
-warning: denote infinite loops with `loop { ... }`
- --> src/main.rs:2:5
- |
-2 | while true {
- | ^^^^^^^^^^ help: use `loop`
- |
-```
+This file is auto-generated by the lint-docs script.
`powerpc64-unknown-linux-musl` | ? | |
`powerpc64-wrs-vxworks` | ? | |
`powerpc64le-unknown-linux-musl` | ? | |
+`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33)
`sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux
`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
`sparc64-unknown-openbsd` | ? | |
Here, the respective tokens can only be used by dependent crates on their respective platforms, but
they will both appear in documentation.
+
+## Add aliases for an item in documentation search
+
+This feature allows you to add alias(es) to an item when using the `rustdoc` search through the
+`doc(alias)` attribute. Example:
+
+```rust,no_run
+#[doc(alias = "x")]
+#[doc(alias = "big")]
+pub struct BigX;
+```
+
+Then, when looking for it through the `rustdoc` search, if you enter "x" or
+"big", search will show the `BigX` struct first.
| ^^^^^^^^^^^^^^^^^^^^^
```
+## missing_crate_level_docs
+
+This lint is **allowed by default**. It detects if there is no documentation
+at the crate root. For example:
+
+```rust
+#![warn(missing_crate_level_docs)]
+```
+
+This will generate the following warning:
+
+```text
+warning: no documentation found for this crate's top-level module
+ |
+ = help: The following guide may be of use:
+ https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html
+```
+
+This is currently "allow" by default, but it is intended to make this a
+warning in the future. This is intended as a means to introduce new users on
+*how* to document their crate by pointing them to some instructions on how to
+get started, without providing overwhelming warnings like `missing_docs`
+might.
+
## missing_doc_code_examples
This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block
8 | | /// ```
| |___________^
```
+
+## invalid_codeblock_attributes
+
+This lint **warns by default**. It detects code block attributes in
+documentation examples that have potentially mis-typed values. For example:
+
+```rust
+/// Example.
+///
+/// ```should-panic
+/// assert_eq!(1, 2);
+/// ```
+pub fn foo() {}
+```
+
+Which will give:
+
+```text
+warning: unknown attribute `should-panic`. Did you mean `should_panic`?
+ --> src/lib.rs:1:1
+ |
+1 | / /// Example.
+2 | | ///
+3 | | /// ```should-panic
+4 | | /// assert_eq!(1, 2);
+5 | | /// ```
+ | |_______^
+ |
+ = note: `#[warn(invalid_codeblock_attributes)]` on by default
+ = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running
+```
+
+In the example above, the correct form is `should_panic`. This helps detect
+typo mistakes for some common attributes.
[unstable-include]: ../unstable-book/language-features/external-doc.html
[issue-include]: https://github.com/rust-lang/rust/issues/44732
-### Add aliases for an item in documentation search
-
-This feature allows you to add alias(es) to an item when using the `rustdoc` search through the
-`doc(alias)` attribute. Example:
-
-```rust,no_run
-#![feature(doc_alias)]
-
-#[doc(alias = "x")]
-#[doc(alias = "big")]
-pub struct BigX;
-```
-
-Then, when looking for it through the `rustdoc` search, if you enter "x" or
-"big", search will show the `BigX` struct first.
-
## Unstable command-line arguments
These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are
+++ /dev/null
-# `doc_alias`
-
-The tracking issue for this feature is: [#50146]
-
-[#50146]: https://github.com/rust-lang/rust/issues/50146
-
-------------------------
-
-You can add alias(es) to an item when using the `rustdoc` search through the
-`doc(alias)` attribute. Example:
-
-```rust,no_run
-#![feature(doc_alias)]
-
-#[doc(alias = "x")]
-#[doc(alias = "big")]
-pub struct BigX;
-```
-
-Then, when looking for it through the `rustdoc` search, if you enter "x" or
-"big", search will show the `BigX` struct first.
-
-Note that this feature is currently hidden behind the `feature(doc_alias)` gate.
If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use.
+## Memory address operands
+
+Sometimes assembly instructions require operands passed via memory addresses/memory locations.
+You have to manually use the memory address syntax specified by the respectively architectures.
+For example, in x86/x86_64 and intel assembly syntax, you should wrap inputs/outputs in `[]`
+to indicate they are memory operands:
+
+```rust,allow_fail
+# #![feature(asm, llvm_asm)]
+# fn load_fpu_control_word(control: u16) {
+unsafe {
+ asm!("fldcw [{}]", in(reg) &control, options(nostack));
+
+ // Previously this would have been written with the deprecated `llvm_asm!` like this
+ llvm_asm!("fldcw $0" :: "m" (control) :: "volatile");
+}
+# }
+```
+
## Options
By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However in many cases, it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better.
Current valid options are:
-1. *volatile* - specifying this is analogous to
+1. `volatile` - specifying this is analogous to
`__asm__ __volatile__ (...)` in gcc/clang.
-2. *alignstack* - certain instructions expect the stack to be
+2. `alignstack` - certain instructions expect the stack to be
aligned a certain way (i.e. SSE) and specifying this indicates to
the compiler to insert its usual stack alignment code
-3. *intel* - use intel syntax instead of the default AT&T.
+3. `intel` - use intel syntax instead of the default AT&T.
```rust
# #![feature(llvm_asm)]
path = "lib.rs"
[dependencies]
-pulldown-cmark = { version = "0.7", default-features = false }
+pulldown-cmark = { version = "0.8", default-features = false }
minifier = "0.0.33"
rayon = { version = "0.3.0", package = "rustc-rayon" }
serde = { version = "1.0", features = ["derive"] }
// reachable in rustdoc generated documentation
if !did.is_local() {
if let Some(traitref) = associated_trait {
- if !cx.renderinfo.borrow().access_levels.is_public(traitref.def_id) {
+ let did = traitref.def_id;
+ if !cx.renderinfo.borrow().access_levels.is_public(did) {
return;
}
- }
- // Skip foreign unstable traits from lists of trait implementations and
- // such. This helps prevent dependencies of the standard library, for
- // example, from getting documented as "traits `u32` implements" which
- // isn't really too helpful.
- if let Some(trait_did) = associated_trait {
- if let Some(stab) = cx.tcx.lookup_stability(trait_did.def_id) {
- if stab.level.is_unstable() {
+ if let Some(stab) = tcx.lookup_stability(did) {
+ if stab.level.is_unstable() && stab.feature == sym::rustc_private {
return;
}
}
if !cx.renderinfo.borrow().access_levels.is_public(did) {
return;
}
+
+ if let Some(stab) = tcx.lookup_stability(did) {
+ if stab.level.is_unstable() && stab.feature == sym::rustc_private {
+ return;
+ }
+ }
}
}
let mut where_predicates =
where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::<Vec<_>>();
- // Type parameters and have a Sized bound by default unless removed with
+ // Type parameters have a Sized bound by default unless removed with
// ?Sized. Scan through the predicates and mark any type parameter with
// a Sized bound, removing the bounds as we find them.
//
},
Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias),
Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
- Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id,
+ Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id,
_ => return res.def_id(),
};
if did.is_local() {
use rustc_span::edition::Edition;
use rustc_span::Span;
use std::borrow::Cow;
-use std::cell::RefCell;
use std::collections::VecDeque;
use std::default::Default;
use std::fmt::Write;
use crate::html::highlight;
use crate::html::toc::TocBuilder;
-use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
+use pulldown_cmark::{html, BrokenLink, CodeBlockKind, CowStr, Event, Options, Parser, Tag};
#[cfg(test)]
mod tests;
if md.is_empty() {
return String::new();
}
- let replacer = |_: &str, s: &str| {
- if let Some(link) = links.iter().find(|link| &*link.original_text == s) {
- Some((link.href.clone(), link.new_text.clone()))
+ let mut replacer = |broken_link: BrokenLink<'_>| {
+ if let Some(link) =
+ links.iter().find(|link| &*link.original_text == broken_link.reference)
+ {
+ Some((link.href.as_str().into(), link.new_text.as_str().into()))
} else {
None
}
};
- let p = Parser::new_with_broken_link_callback(md, opts(), Some(&replacer));
+ let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer));
let mut s = String::with_capacity(md.len() * 3 / 2);
return String::new();
}
- let replacer = |_: &str, s: &str| {
- if let Some(link) = links.iter().find(|link| &*link.original_text == s) {
- Some((link.href.clone(), link.new_text.clone()))
+ let mut replacer = |broken_link: BrokenLink<'_>| {
+ if let Some(link) =
+ links.iter().find(|link| &*link.original_text == broken_link.reference)
+ {
+ Some((link.href.as_str().into(), link.new_text.as_str().into()))
} else {
None
}
let p = Parser::new_with_broken_link_callback(
md,
Options::ENABLE_STRIKETHROUGH,
- Some(&replacer),
+ Some(&mut replacer),
);
let mut s = String::new();
}
let mut links = vec![];
- let shortcut_links = RefCell::new(vec![]);
+ let mut shortcut_links = vec![];
{
let locate = |s: &str| unsafe {
}
};
- let push = |_: &str, s: &str| {
- shortcut_links.borrow_mut().push((s.to_owned(), locate(s)));
+ let mut push = |link: BrokenLink<'_>| {
+ // FIXME: use `link.span` instead of `locate`
+ // (doing it now includes the `[]` as well as the text)
+ shortcut_links.push((link.reference.to_owned(), locate(link.reference)));
None
};
- let p = Parser::new_with_broken_link_callback(md, opts(), Some(&push));
+ let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push));
// There's no need to thread an IdMap through to here because
// the IDs generated aren't going to be emitted anywhere.
}
}
- let mut shortcut_links = shortcut_links.into_inner();
- links.extend(shortcut_links.drain(..));
+ links.append(&mut shortcut_links);
links
}
let kind = if let Some(intermediate) = self.check_full_res(
TypeNS,
&intermediate_path,
- Some(module_id),
+ module_id,
current_item,
extra_fragment,
) {
fn macro_resolve(
&self,
path_str: &'a str,
- parent_id: Option<DefId>,
+ module_id: DefId,
) -> Result<Res, ResolutionFailure<'a>> {
let cx = self.cx;
let path = ast::Path::from_ident(Ident::from_str(path_str));
if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
return Some(Ok(res.map_id(|_| panic!("unexpected id"))));
}
- if let Some(module_id) = parent_id {
- debug!("resolving {} as a macro in the module {:?}", path_str, module_id);
- if let Ok((_, res)) =
- resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id)
- {
- // don't resolve builtins like `#[derive]`
- if let Res::Def(..) = res {
- let res = res.map_id(|_| panic!("unexpected node_id"));
- return Some(Ok(res));
- }
+ debug!("resolving {} as a macro in the module {:?}", path_str, module_id);
+ if let Ok((_, res)) =
+ resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id)
+ {
+ // don't resolve builtins like `#[derive]`
+ if let Res::Def(..) = res {
+ let res = res.map_id(|_| panic!("unexpected node_id"));
+ return Some(Ok(res));
}
- } else {
- debug!("attempting to resolve item without parent module: {}", path_str);
- return Some(Err(ResolutionFailure::NoParentItem));
}
None
})
.unwrap_or_else(|| {
let mut split = path_str.rsplitn(2, "::");
if let Some((parent, base)) = split.next().and_then(|x| Some((split.next()?, x))) {
- if let Some(res) = self.check_full_res(TypeNS, parent, parent_id, &None, &None) {
+ if let Some(res) = self.check_full_res(TypeNS, parent, module_id, &None, &None) {
return Err(if matches!(res, Res::PrimTy(_)) {
ResolutionFailure::NoPrimitiveAssocItem {
res,
});
}
}
- Err(ResolutionFailure::NotInScope {
- module_id: parent_id.expect("already saw `Some` when resolving as a macro"),
- name: path_str.into(),
- })
+ Err(ResolutionFailure::NotInScope { module_id, name: path_str.into() })
})
}
+
/// Resolves a string as a path within a particular namespace. Also returns an optional
/// URL fragment in the case of variants and methods.
fn resolve<'path>(
path_str: &'path str,
ns: Namespace,
current_item: &Option<String>,
- parent_id: Option<DefId>,
+ module_id: DefId,
extra_fragment: &Option<String>,
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
let cx = self.cx;
- // In case we're in a module, try to resolve the relative path.
- if let Some(module_id) = parent_id {
- let result = cx.enter_resolver(|resolver| {
- resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
- });
- debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
- let result = match result {
- Ok((_, Res::Err)) => Err(()),
- x => x,
- };
+ let result = cx.enter_resolver(|resolver| {
+ resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+ });
+ debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
+ let result = match result {
+ Ok((_, Res::Err)) => Err(()),
+ x => x,
+ };
- if let Ok((_, res)) = result {
- let res = res.map_id(|_| panic!("unexpected node_id"));
- // In case this is a trait item, skip the
- // early return and try looking for the trait.
- let value = match res {
- Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true,
- Res::Def(DefKind::AssocTy, _) => false,
- Res::Def(DefKind::Variant, _) => {
- return handle_variant(cx, res, extra_fragment);
- }
- // Not a trait item; just return what we found.
- Res::PrimTy(..) => {
- if extra_fragment.is_some() {
- return Err(ErrorKind::AnchorFailure(
- AnchorFailure::RustdocAnchorConflict(res),
- ));
- }
- return Ok((res, Some(path_str.to_owned())));
- }
- Res::Def(DefKind::Mod, _) => {
- return Ok((res, extra_fragment.clone()));
- }
- _ => {
- return Ok((res, extra_fragment.clone()));
+ if let Ok((_, res)) = result {
+ let res = res.map_id(|_| panic!("unexpected node_id"));
+ // In case this is a trait item, skip the
+ // early return and try looking for the trait.
+ let value = match res {
+ Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true,
+ Res::Def(DefKind::AssocTy, _) => false,
+ Res::Def(DefKind::Variant, _) => {
+ return handle_variant(cx, res, extra_fragment);
+ }
+ // Not a trait item; just return what we found.
+ Res::PrimTy(..) => {
+ if extra_fragment.is_some() {
+ return Err(ErrorKind::AnchorFailure(
+ AnchorFailure::RustdocAnchorConflict(res),
+ ));
}
- };
-
- if value != (ns == ValueNS) {
- return Err(ResolutionFailure::WrongNamespace(res, ns).into());
+ return Ok((res, Some(path_str.to_owned())));
+ }
+ Res::Def(DefKind::Mod, _) => {
+ return Ok((res, extra_fragment.clone()));
}
- } else if let Some((path, prim)) = is_primitive(path_str, ns) {
- if extra_fragment.is_some() {
- return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(
- prim,
- )));
+ _ => {
+ return Ok((res, extra_fragment.clone()));
}
- return Ok((prim, Some(path.to_owned())));
+ };
+
+ if value != (ns == ValueNS) {
+ return Err(ResolutionFailure::WrongNamespace(res, ns).into());
}
+ } else if let Some((path, prim)) = is_primitive(path_str, ns) {
+ if extra_fragment.is_some() {
+ return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(prim)));
+ }
+ return Ok((prim, Some(path.to_owned())));
+ }
- // Try looking for methods and associated items.
- let mut split = path_str.rsplitn(2, "::");
- // this can be an `unwrap()` because we ensure the link is never empty
- let item_name = Symbol::intern(split.next().unwrap());
- let path_root = split
- .next()
- .map(|f| {
- if f == "self" || f == "Self" {
- if let Some(name) = current_item.as_ref() {
- return name.clone();
- }
- }
- f.to_owned()
- })
- // If there's no `::`, it's not an associated item.
- // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
- .ok_or_else(|| {
- debug!("found no `::`, assumming {} was correctly not in scope", item_name);
- ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() }
- })?;
-
- if let Some((path, prim)) = is_primitive(&path_root, TypeNS) {
- let impls = primitive_impl(cx, &path)
- .ok_or_else(|| ResolutionFailure::NoPrimitiveImpl(prim, path_root.into()))?;
- for &impl_ in impls {
- let link = cx
- .tcx
- .associated_items(impl_)
- .find_by_name_and_namespace(
- cx.tcx,
- Ident::with_dummy_span(item_name),
- ns,
- impl_,
- )
- .map(|item| match item.kind {
- ty::AssocKind::Fn => "method",
- ty::AssocKind::Const => "associatedconstant",
- ty::AssocKind::Type => "associatedtype",
- })
- .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name))));
- if let Some(link) = link {
- return Ok(link);
+ // Try looking for methods and associated items.
+ let mut split = path_str.rsplitn(2, "::");
+ // this can be an `unwrap()` because we ensure the link is never empty
+ let item_name = Symbol::intern(split.next().unwrap());
+ let path_root = split
+ .next()
+ .map(|f| {
+ if f == "self" || f == "Self" {
+ if let Some(name) = current_item.as_ref() {
+ return name.clone();
}
}
- debug!(
- "returning primitive error for {}::{} in {} namespace",
- path,
- item_name,
- ns.descr()
- );
- return Err(ResolutionFailure::NoPrimitiveAssocItem {
- res: prim,
- prim_name: path,
- assoc_item: item_name,
+ f.to_owned()
+ })
+ // If there's no `::`, it's not an associated item.
+ // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved.
+ .ok_or_else(|| {
+ debug!("found no `::`, assumming {} was correctly not in scope", item_name);
+ ResolutionFailure::NotInScope { module_id, name: item_name.to_string().into() }
+ })?;
+
+ if let Some((path, prim)) = is_primitive(&path_root, TypeNS) {
+ let impls = primitive_impl(cx, &path)
+ .ok_or_else(|| ResolutionFailure::NoPrimitiveImpl(prim, path_root.into()))?;
+ for &impl_ in impls {
+ let link = cx
+ .tcx
+ .associated_items(impl_)
+ .find_by_name_and_namespace(
+ cx.tcx,
+ Ident::with_dummy_span(item_name),
+ ns,
+ impl_,
+ )
+ .map(|item| match item.kind {
+ ty::AssocKind::Fn => "method",
+ ty::AssocKind::Const => "associatedconstant",
+ ty::AssocKind::Type => "associatedtype",
+ })
+ .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name))));
+ if let Some(link) = link {
+ return Ok(link);
}
- .into());
}
+ debug!(
+ "returning primitive error for {}::{} in {} namespace",
+ path,
+ item_name,
+ ns.descr()
+ );
+ return Err(ResolutionFailure::NoPrimitiveAssocItem {
+ res: prim,
+ prim_name: path,
+ assoc_item: item_name,
+ }
+ .into());
+ }
- let ty_res = cx
- .enter_resolver(|resolver| {
- // only types can have associated items
- resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id)
- })
- .map(|(_, res)| res);
- let ty_res = match ty_res {
- Err(()) | Ok(Res::Err) => {
- return if ns == Namespace::ValueNS {
- self.variant_field(path_str, current_item, module_id, extra_fragment)
- } else {
- // See if it only broke because of the namespace.
- let kind = cx.enter_resolver(|resolver| {
- // NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it)
- for &ns in &[MacroNS, ValueNS] {
- match resolver
- .resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id)
- {
- Ok((_, Res::Err)) | Err(()) => {}
- Ok((_, res)) => {
- let res = res.map_id(|_| panic!("unexpected node_id"));
- return ResolutionFailure::CannotHaveAssociatedItems(
- res, ns,
- );
- }
+ let ty_res = cx
+ .enter_resolver(|resolver| {
+ // only types can have associated items
+ resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id)
+ })
+ .map(|(_, res)| res);
+ let ty_res = match ty_res {
+ Err(()) | Ok(Res::Err) => {
+ return if ns == Namespace::ValueNS {
+ self.variant_field(path_str, current_item, module_id, extra_fragment)
+ } else {
+ // See if it only broke because of the namespace.
+ let kind = cx.enter_resolver(|resolver| {
+ // NOTE: this doesn't use `check_full_res` because we explicitly want to ignore `TypeNS` (we already checked it)
+ for &ns in &[MacroNS, ValueNS] {
+ match resolver
+ .resolve_str_path_error(DUMMY_SP, &path_root, ns, module_id)
+ {
+ Ok((_, Res::Err)) | Err(()) => {}
+ Ok((_, res)) => {
+ let res = res.map_id(|_| panic!("unexpected node_id"));
+ return ResolutionFailure::CannotHaveAssociatedItems(res, ns);
}
}
- ResolutionFailure::NotInScope { module_id, name: path_root.into() }
- });
- Err(kind.into())
- };
- }
- Ok(res) => res,
- };
- let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
- let res = match ty_res {
- Res::Def(
- DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias,
- did,
- ) => {
- debug!("looking for associated item named {} for item {:?}", item_name, did);
- // Checks if item_name belongs to `impl SomeItem`
- let assoc_item = cx
- .tcx
- .inherent_impls(did)
- .iter()
- .flat_map(|&imp| {
- cx.tcx.associated_items(imp).find_by_name_and_namespace(
- cx.tcx,
- Ident::with_dummy_span(item_name),
- ns,
- imp,
- )
- })
- .map(|item| (item.kind, item.def_id))
- // There should only ever be one associated item that matches from any inherent impl
- .next()
- // Check if item_name belongs to `impl SomeTrait for SomeItem`
- // This gives precedence to `impl SomeItem`:
- // Although having both would be ambiguous, use impl version for compat. sake.
- // To handle that properly resolve() would have to support
- // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
- .or_else(|| {
- let kind = resolve_associated_trait_item(
- did, module_id, item_name, ns, &self.cx,
- );
- debug!("got associated item kind {:?}", kind);
- kind
- });
-
- if let Some((kind, id)) = assoc_item {
- let out = match kind {
- ty::AssocKind::Fn => "method",
- ty::AssocKind::Const => "associatedconstant",
- ty::AssocKind::Type => "associatedtype",
- };
- Some(if extra_fragment.is_some() {
- Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(
- ty_res,
- )))
- } else {
- // HACK(jynelson): `clean` expects the type, not the associated item.
- // but the disambiguator logic expects the associated item.
- // Store the kind in a side channel so that only the disambiguator logic looks at it.
- self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
- Ok((ty_res, Some(format!("{}.{}", out, item_name))))
- })
- } else if ns == Namespace::ValueNS {
- debug!("looking for variants or fields named {} for {:?}", item_name, did);
- match cx.tcx.type_of(did).kind() {
- ty::Adt(def, _) => {
- let field = if def.is_enum() {
- def.all_fields().find(|item| item.ident.name == item_name)
- } else {
- def.non_enum_variant()
- .fields
- .iter()
- .find(|item| item.ident.name == item_name)
- };
- field.map(|item| {
- if extra_fragment.is_some() {
- let res = Res::Def(
- if def.is_enum() {
- DefKind::Variant
- } else {
- DefKind::Field
- },
- item.did,
- );
- Err(ErrorKind::AnchorFailure(
- AnchorFailure::RustdocAnchorConflict(res),
- ))
- } else {
- Ok((
- ty_res,
- Some(format!(
- "{}.{}",
- if def.is_enum() {
- "variant"
- } else {
- "structfield"
- },
- item.ident
- )),
- ))
- }
- })
- }
- _ => None,
}
- } else {
- // We already know this isn't in ValueNS, so no need to check variant_field
- return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into());
- }
- }
- Res::Def(DefKind::Trait, did) => cx
+ ResolutionFailure::NotInScope { module_id, name: path_root.into() }
+ });
+ Err(kind.into())
+ };
+ }
+ Ok(res) => res,
+ };
+ let ty_res = ty_res.map_id(|_| panic!("unexpected node_id"));
+ let res = match ty_res {
+ Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did) => {
+ debug!("looking for associated item named {} for item {:?}", item_name, did);
+ // Checks if item_name belongs to `impl SomeItem`
+ let assoc_item = cx
.tcx
- .associated_items(did)
- .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, did)
- .map(|item| {
- let kind = match item.kind {
- ty::AssocKind::Const => "associatedconstant",
- ty::AssocKind::Type => "associatedtype",
- ty::AssocKind::Fn => {
- if item.defaultness.has_value() {
- "method"
+ .inherent_impls(did)
+ .iter()
+ .flat_map(|&imp| {
+ cx.tcx.associated_items(imp).find_by_name_and_namespace(
+ cx.tcx,
+ Ident::with_dummy_span(item_name),
+ ns,
+ imp,
+ )
+ })
+ .map(|item| (item.kind, item.def_id))
+ // There should only ever be one associated item that matches from any inherent impl
+ .next()
+ // Check if item_name belongs to `impl SomeTrait for SomeItem`
+ // This gives precedence to `impl SomeItem`:
+ // Although having both would be ambiguous, use impl version for compat. sake.
+ // To handle that properly resolve() would have to support
+ // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
+ .or_else(|| {
+ let kind =
+ resolve_associated_trait_item(did, module_id, item_name, ns, &self.cx);
+ debug!("got associated item kind {:?}", kind);
+ kind
+ });
+
+ if let Some((kind, id)) = assoc_item {
+ let out = match kind {
+ ty::AssocKind::Fn => "method",
+ ty::AssocKind::Const => "associatedconstant",
+ ty::AssocKind::Type => "associatedtype",
+ };
+ Some(if extra_fragment.is_some() {
+ Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
+ } else {
+ // HACK(jynelson): `clean` expects the type, not the associated item.
+ // but the disambiguator logic expects the associated item.
+ // Store the kind in a side channel so that only the disambiguator logic looks at it.
+ self.kind_side_channel.set(Some((kind.as_def_kind(), id)));
+ Ok((ty_res, Some(format!("{}.{}", out, item_name))))
+ })
+ } else if ns == Namespace::ValueNS {
+ debug!("looking for variants or fields named {} for {:?}", item_name, did);
+ match cx.tcx.type_of(did).kind() {
+ ty::Adt(def, _) => {
+ let field = if def.is_enum() {
+ def.all_fields().find(|item| item.ident.name == item_name)
+ } else {
+ def.non_enum_variant()
+ .fields
+ .iter()
+ .find(|item| item.ident.name == item_name)
+ };
+ field.map(|item| {
+ if extra_fragment.is_some() {
+ let res = Res::Def(
+ if def.is_enum() {
+ DefKind::Variant
+ } else {
+ DefKind::Field
+ },
+ item.did,
+ );
+ Err(ErrorKind::AnchorFailure(
+ AnchorFailure::RustdocAnchorConflict(res),
+ ))
} else {
- "tymethod"
+ Ok((
+ ty_res,
+ Some(format!(
+ "{}.{}",
+ if def.is_enum() { "variant" } else { "structfield" },
+ item.ident
+ )),
+ ))
}
- }
- };
-
- if extra_fragment.is_some() {
- Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(
- ty_res,
- )))
- } else {
- let res = Res::Def(item.kind.as_def_kind(), item.def_id);
- Ok((res, Some(format!("{}.{}", kind, item_name))))
+ })
}
- }),
- _ => None,
- };
- res.unwrap_or_else(|| {
- if ns == Namespace::ValueNS {
- self.variant_field(path_str, current_item, module_id, extra_fragment)
+ _ => None,
+ }
} else {
- Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into())
+ // We already know this isn't in ValueNS, so no need to check variant_field
+ return Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into());
}
- })
- } else {
- debug!("attempting to resolve item without parent module: {}", path_str);
- Err(ResolutionFailure::NoParentItem.into())
- }
+ }
+ Res::Def(DefKind::Trait, did) => cx
+ .tcx
+ .associated_items(did)
+ .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, did)
+ .map(|item| {
+ let kind = match item.kind {
+ ty::AssocKind::Const => "associatedconstant",
+ ty::AssocKind::Type => "associatedtype",
+ ty::AssocKind::Fn => {
+ if item.defaultness.has_value() {
+ "method"
+ } else {
+ "tymethod"
+ }
+ }
+ };
+
+ if extra_fragment.is_some() {
+ Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res)))
+ } else {
+ let res = Res::Def(item.kind.as_def_kind(), item.def_id);
+ Ok((res, Some(format!("{}.{}", kind, item_name))))
+ }
+ }),
+ _ => None,
+ };
+ res.unwrap_or_else(|| {
+ if ns == Namespace::ValueNS {
+ self.variant_field(path_str, current_item, module_id, extra_fragment)
+ } else {
+ Err(ResolutionFailure::NoAssocItem(ty_res, item_name).into())
+ }
+ })
}
/// Used for reporting better errors.
&self,
ns: Namespace,
path_str: &str,
- base_node: Option<DefId>,
+ module_id: DefId,
current_item: &Option<String>,
extra_fragment: &Option<String>,
) -> Option<Res> {
};
// cannot be used for macro namespace
let check_full_res = |this: &Self, ns| {
- let result = this.resolve(path_str, ns, current_item, base_node, extra_fragment);
+ let result = this.resolve(path_str, ns, current_item, module_id, extra_fragment);
check_full_res_inner(this, result.map(|(res, _)| res))
};
let check_full_res_macro = |this: &Self| {
- let result = this.macro_resolve(path_str, base_node);
+ let result = this.macro_resolve(path_str, module_id);
check_full_res_inner(this, result.map_err(ErrorKind::from))
};
match ns {
self.mod_ids.push(item.def_id);
}
- let cx = self.cx;
let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
trace!("got documentation '{}'", dox);
});
for (ori_link, link_range) in markdown_links(&dox) {
- trace!("considering link '{}'", ori_link);
+ self.resolve_link(
+ &mut item,
+ &dox,
+ ¤t_item,
+ parent_node,
+ &parent_name,
+ ori_link,
+ link_range,
+ );
+ }
+
+ if item.is_mod() && !item.attrs.inner_docs {
+ self.mod_ids.push(item.def_id);
+ }
+
+ if item.is_mod() {
+ let ret = self.fold_item_recur(item);
+
+ self.mod_ids.pop();
- // Bail early for real links.
- if ori_link.contains('/') {
- continue;
+ ret
+ } else {
+ self.fold_item_recur(item)
+ }
+ }
+}
+
+impl LinkCollector<'_, '_> {
+ fn resolve_link(
+ &self,
+ item: &mut Item,
+ dox: &str,
+ current_item: &Option<String>,
+ parent_node: Option<DefId>,
+ parent_name: &Option<String>,
+ ori_link: String,
+ link_range: Option<Range<usize>>,
+ ) {
+ trace!("considering link '{}'", ori_link);
+
+ // Bail early for real links.
+ if ori_link.contains('/') {
+ return;
+ }
+
+ // [] is mostly likely not supposed to be a link
+ if ori_link.is_empty() {
+ return;
+ }
+
+ let cx = self.cx;
+ let link = ori_link.replace("`", "");
+ let parts = link.split('#').collect::<Vec<_>>();
+ let (link, extra_fragment) = if parts.len() > 2 {
+ anchor_failure(cx, &item, &link, dox, link_range, AnchorFailure::MultipleAnchors);
+ return;
+ } else if parts.len() == 2 {
+ if parts[0].trim().is_empty() {
+ // This is an anchor to an element of the current page, nothing to do in here!
+ return;
}
+ (parts[0], Some(parts[1].to_owned()))
+ } else {
+ (parts[0], None)
+ };
+ let resolved_self;
+ let link_text;
+ let mut path_str;
+ let disambiguator;
+ let (mut res, mut fragment) = {
+ path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) {
+ disambiguator = Some(d);
+ path
+ } else {
+ disambiguator = None;
+ &link
+ }
+ .trim();
- // [] is mostly likely not supposed to be a link
- if ori_link.is_empty() {
- continue;
+ if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) {
+ return;
}
- let link = ori_link.replace("`", "");
- let parts = link.split('#').collect::<Vec<_>>();
- let (link, extra_fragment) = if parts.len() > 2 {
- anchor_failure(cx, &item, &link, &dox, link_range, AnchorFailure::MultipleAnchors);
- continue;
- } else if parts.len() == 2 {
- if parts[0].trim().is_empty() {
- // This is an anchor to an element of the current page, nothing to do in here!
- continue;
- }
- (parts[0], Some(parts[1].to_owned()))
+ // We stripped `()` and `!` when parsing the disambiguator.
+ // Add them back to be displayed, but not prefix disambiguators.
+ link_text = disambiguator
+ .map(|d| d.display_for(path_str))
+ .unwrap_or_else(|| path_str.to_owned());
+
+ // In order to correctly resolve intra-doc-links we need to
+ // pick a base AST node to work from. If the documentation for
+ // this module came from an inner comment (//!) then we anchor
+ // our name resolution *inside* the module. If, on the other
+ // hand it was an outer comment (///) then we anchor the name
+ // resolution in the parent module on the basis that the names
+ // used are more likely to be intended to be parent names. For
+ // this, we set base_node to None for inner comments since
+ // we've already pushed this node onto the resolution stack but
+ // for outer comments we explicitly try and resolve against the
+ // parent_node first.
+ let base_node = if item.is_mod() && item.attrs.inner_docs {
+ self.mod_ids.last().copied()
} else {
- (parts[0], None)
+ parent_node
};
- let resolved_self;
- let link_text;
- let mut path_str;
- let disambiguator;
- let (mut res, mut fragment) = {
- path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) {
- disambiguator = Some(d);
- path
- } else {
- disambiguator = None;
- &link
- }
- .trim();
- if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) {
- continue;
+ let module_id = if let Some(id) = base_node {
+ id
+ } else {
+ debug!("attempting to resolve item without parent module: {}", path_str);
+ let err_kind = ResolutionFailure::NoParentItem.into();
+ resolution_failure(
+ self,
+ &item,
+ path_str,
+ disambiguator,
+ dox,
+ link_range,
+ smallvec![err_kind],
+ );
+ return;
+ };
+
+ // replace `Self` with suitable item's parent name
+ if path_str.starts_with("Self::") {
+ if let Some(ref name) = parent_name {
+ resolved_self = format!("{}::{}", name, &path_str[6..]);
+ path_str = &resolved_self;
}
+ }
- // We stripped `()` and `!` when parsing the disambiguator.
- // Add them back to be displayed, but not prefix disambiguators.
- link_text = disambiguator
- .map(|d| d.display_for(path_str))
- .unwrap_or_else(|| path_str.to_owned());
-
- // In order to correctly resolve intra-doc-links we need to
- // pick a base AST node to work from. If the documentation for
- // this module came from an inner comment (//!) then we anchor
- // our name resolution *inside* the module. If, on the other
- // hand it was an outer comment (///) then we anchor the name
- // resolution in the parent module on the basis that the names
- // used are more likely to be intended to be parent names. For
- // this, we set base_node to None for inner comments since
- // we've already pushed this node onto the resolution stack but
- // for outer comments we explicitly try and resolve against the
- // parent_node first.
- let base_node = if item.is_mod() && item.attrs.inner_docs {
- self.mod_ids.last().copied()
- } else {
- parent_node
- };
+ match self.resolve_with_disambiguator(
+ disambiguator,
+ item,
+ dox,
+ path_str,
+ current_item,
+ module_id,
+ extra_fragment,
+ &ori_link,
+ link_range.clone(),
+ ) {
+ Some(x) => x,
+ None => return,
+ }
+ };
- // replace `Self` with suitable item's parent name
- if path_str.starts_with("Self::") {
- if let Some(ref name) = parent_name {
- resolved_self = format!("{}::{}", name, &path_str[6..]);
- path_str = &resolved_self;
+ // Check for a primitive which might conflict with a module
+ // Report the ambiguity and require that the user specify which one they meant.
+ // FIXME: could there ever be a primitive not in the type namespace?
+ if matches!(
+ disambiguator,
+ None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive)
+ ) && !matches!(res, Res::PrimTy(_))
+ {
+ if let Some((path, prim)) = is_primitive(path_str, TypeNS) {
+ // `prim@char`
+ if matches!(disambiguator, Some(Disambiguator::Primitive)) {
+ if fragment.is_some() {
+ anchor_failure(
+ cx,
+ &item,
+ path_str,
+ dox,
+ link_range,
+ AnchorFailure::RustdocAnchorConflict(prim),
+ );
+ return;
}
+ res = prim;
+ fragment = Some(path.to_owned());
+ } else {
+ // `[char]` when a `char` module is in scope
+ let candidates = vec![res, prim];
+ ambiguity_error(cx, &item, path_str, dox, link_range, candidates);
+ return;
}
+ }
+ }
- match disambiguator.map(Disambiguator::ns) {
- Some(ns @ (ValueNS | TypeNS)) => {
- match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment)
- {
- Ok(res) => res,
- Err(ErrorKind::Resolve(box mut kind)) => {
- // We only looked in one namespace. Try to give a better error if possible.
- if kind.full_res().is_none() {
- let other_ns = if ns == ValueNS { TypeNS } else { ValueNS };
- for &new_ns in &[other_ns, MacroNS] {
- if let Some(res) = self.check_full_res(
- new_ns,
- path_str,
- base_node,
- ¤t_item,
- &extra_fragment,
- ) {
- kind = ResolutionFailure::WrongNamespace(res, ns);
- break;
- }
- }
- }
- resolution_failure(
- self,
- &item,
- path_str,
- disambiguator,
- &dox,
- link_range,
- smallvec![kind],
- );
- // This could just be a normal link or a broken link
- // we could potentially check if something is
- // "intra-doc-link-like" and warn in that case.
- continue;
- }
- Err(ErrorKind::AnchorFailure(msg)) => {
- anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
- continue;
- }
- }
+ let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| {
+ // The resolved item did not match the disambiguator; give a better error than 'not found'
+ let msg = format!("incompatible link kind for `{}`", path_str);
+ report_diagnostic(cx, &msg, &item, dox, &link_range, |diag, sp| {
+ let note = format!(
+ "this link resolved to {} {}, which is not {} {}",
+ resolved.article(),
+ resolved.descr(),
+ specified.article(),
+ specified.descr()
+ );
+ diag.note(¬e);
+ suggest_disambiguator(resolved, diag, path_str, dox, sp, &link_range);
+ });
+ };
+ if let Res::PrimTy(_) = res {
+ match disambiguator {
+ Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {
+ item.attrs.links.push(ItemLink {
+ link: ori_link,
+ link_text: path_str.to_owned(),
+ did: None,
+ fragment,
+ });
+ }
+ Some(other) => {
+ report_mismatch(other, Disambiguator::Primitive);
+ return;
+ }
+ }
+ } else {
+ debug!("intra-doc link to {} resolved to {:?}", path_str, res);
+
+ // Disallow e.g. linking to enums with `struct@`
+ if let Res::Def(kind, _) = res {
+ debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
+ match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) {
+ | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
+ // NOTE: this allows 'method' to mean both normal functions and associated functions
+ // This can't cause ambiguity because both are in the same namespace.
+ | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
+ // These are namespaces; allow anything in the namespace to match
+ | (_, Some(Disambiguator::Namespace(_)))
+ // If no disambiguator given, allow anything
+ | (_, None)
+ // All of these are valid, so do nothing
+ => {}
+ (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
+ (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
+ report_mismatch(specified, Disambiguator::Kind(kind));
+ return;
}
- None => {
- // Try everything!
- let mut candidates = PerNS {
- macro_ns: self
- .macro_resolve(path_str, base_node)
- .map(|res| (res, extra_fragment.clone())),
- type_ns: match self.resolve(
- path_str,
- TypeNS,
- ¤t_item,
- base_node,
- &extra_fragment,
- ) {
- Ok(res) => {
- debug!("got res in TypeNS: {:?}", res);
- Ok(res)
- }
- Err(ErrorKind::AnchorFailure(msg)) => {
- anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
- continue;
- }
- Err(ErrorKind::Resolve(box kind)) => Err(kind),
- },
- value_ns: match self.resolve(
- path_str,
- ValueNS,
- ¤t_item,
- base_node,
- &extra_fragment,
- ) {
- Ok(res) => Ok(res),
- Err(ErrorKind::AnchorFailure(msg)) => {
- anchor_failure(cx, &item, &ori_link, &dox, link_range, msg);
- continue;
- }
- Err(ErrorKind::Resolve(box kind)) => Err(kind),
- }
- .and_then(|(res, fragment)| {
- // Constructors are picked up in the type namespace.
- match res {
- Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => {
- Err(ResolutionFailure::WrongNamespace(res, TypeNS))
- }
- _ => match (fragment, extra_fragment) {
- (Some(fragment), Some(_)) => {
- // Shouldn't happen but who knows?
- Ok((res, Some(fragment)))
- }
- (fragment, None) | (None, fragment) => Ok((res, fragment)),
- },
- }
- }),
- };
+ }
+ }
- let len = candidates.iter().filter(|res| res.is_ok()).count();
+ // item can be non-local e.g. when using #[doc(primitive = "pointer")]
+ if let Some((src_id, dst_id)) = res
+ .opt_def_id()
+ .and_then(|def_id| def_id.as_local())
+ .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id)))
+ {
+ use rustc_hir::def_id::LOCAL_CRATE;
- if len == 0 {
- resolution_failure(
- self,
- &item,
- path_str,
- disambiguator,
- &dox,
- link_range,
- candidates.into_iter().filter_map(|res| res.err()).collect(),
- );
- // this could just be a normal link
- continue;
- }
+ let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id);
+ let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id);
- if len == 1 {
- candidates.into_iter().filter_map(|res| res.ok()).next().unwrap()
- } else if len == 2 && is_derive_trait_collision(&candidates) {
- candidates.type_ns.unwrap()
- } else {
- if is_derive_trait_collision(&candidates) {
- candidates.macro_ns = Err(ResolutionFailure::Dummy);
- }
- // If we're reporting an ambiguity, don't mention the namespaces that failed
- let candidates =
- candidates.map(|candidate| candidate.ok().map(|(res, _)| res));
- ambiguity_error(
- cx,
- &item,
- path_str,
- &dox,
- link_range,
- candidates.present_items().collect(),
- );
- continue;
- }
- }
- Some(MacroNS) => {
- match self.macro_resolve(path_str, base_node) {
- Ok(res) => (res, extra_fragment),
- Err(mut kind) => {
- // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible.
- for &ns in &[TypeNS, ValueNS] {
- if let Some(res) = self.check_full_res(
- ns,
- path_str,
- base_node,
- ¤t_item,
- &extra_fragment,
- ) {
- kind = ResolutionFailure::WrongNamespace(res, MacroNS);
- break;
- }
- }
- resolution_failure(
- self,
- &item,
+ if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src)
+ && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst)
+ {
+ privacy_error(cx, &item, &path_str, dox, link_range);
+ return;
+ }
+ }
+ let id = register_res(cx, res);
+ item.attrs.links.push(ItemLink { link: ori_link, link_text, did: Some(id), fragment });
+ }
+ }
+
+ fn resolve_with_disambiguator(
+ &self,
+ disambiguator: Option<Disambiguator>,
+ item: &mut Item,
+ dox: &str,
+ path_str: &str,
+ current_item: &Option<String>,
+ base_node: DefId,
+ extra_fragment: Option<String>,
+ ori_link: &str,
+ link_range: Option<Range<usize>>,
+ ) -> Option<(Res, Option<String>)> {
+ match disambiguator.map(Disambiguator::ns) {
+ Some(ns @ (ValueNS | TypeNS)) => {
+ match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) {
+ Ok(res) => Some(res),
+ Err(ErrorKind::Resolve(box mut kind)) => {
+ // We only looked in one namespace. Try to give a better error if possible.
+ if kind.full_res().is_none() {
+ let other_ns = if ns == ValueNS { TypeNS } else { ValueNS };
+ for &new_ns in &[other_ns, MacroNS] {
+ if let Some(res) = self.check_full_res(
+ new_ns,
path_str,
- disambiguator,
- &dox,
- link_range,
- smallvec![kind],
- );
- continue;
+ base_node,
+ ¤t_item,
+ &extra_fragment,
+ ) {
+ kind = ResolutionFailure::WrongNamespace(res, ns);
+ break;
+ }
}
}
+ resolution_failure(
+ self,
+ &item,
+ path_str,
+ disambiguator,
+ dox,
+ link_range,
+ smallvec![kind],
+ );
+ // This could just be a normal link or a broken link
+ // we could potentially check if something is
+ // "intra-doc-link-like" and warn in that case.
+ return None;
}
- }
- };
-
- // Check for a primitive which might conflict with a module
- // Report the ambiguity and require that the user specify which one they meant.
- // FIXME: could there ever be a primitive not in the type namespace?
- if matches!(
- disambiguator,
- None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive)
- ) && !matches!(res, Res::PrimTy(_))
- {
- if let Some((path, prim)) = is_primitive(path_str, TypeNS) {
- // `prim@char`
- if matches!(disambiguator, Some(Disambiguator::Primitive)) {
- if fragment.is_some() {
- anchor_failure(
- cx,
- &item,
- path_str,
- &dox,
- link_range,
- AnchorFailure::RustdocAnchorConflict(prim),
- );
- continue;
- }
- res = prim;
- fragment = Some(path.to_owned());
- } else {
- // `[char]` when a `char` module is in scope
- let candidates = vec![res, prim];
- ambiguity_error(cx, &item, path_str, &dox, link_range, candidates);
- continue;
+ Err(ErrorKind::AnchorFailure(msg)) => {
+ anchor_failure(self.cx, &item, &ori_link, dox, link_range, msg);
+ return None;
}
}
}
+ None => {
+ // Try everything!
+ let mut candidates = PerNS {
+ macro_ns: self
+ .macro_resolve(path_str, base_node)
+ .map(|res| (res, extra_fragment.clone())),
+ type_ns: match self.resolve(
+ path_str,
+ TypeNS,
+ ¤t_item,
+ base_node,
+ &extra_fragment,
+ ) {
+ Ok(res) => {
+ debug!("got res in TypeNS: {:?}", res);
+ Ok(res)
+ }
+ Err(ErrorKind::AnchorFailure(msg)) => {
+ anchor_failure(self.cx, &item, ori_link, dox, link_range, msg);
+ return None;
+ }
+ Err(ErrorKind::Resolve(box kind)) => Err(kind),
+ },
+ value_ns: match self.resolve(
+ path_str,
+ ValueNS,
+ ¤t_item,
+ base_node,
+ &extra_fragment,
+ ) {
+ Ok(res) => Ok(res),
+ Err(ErrorKind::AnchorFailure(msg)) => {
+ anchor_failure(self.cx, &item, ori_link, dox, link_range, msg);
+ return None;
+ }
+ Err(ErrorKind::Resolve(box kind)) => Err(kind),
+ }
+ .and_then(|(res, fragment)| {
+ // Constructors are picked up in the type namespace.
+ match res {
+ Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => {
+ Err(ResolutionFailure::WrongNamespace(res, TypeNS))
+ }
+ _ => match (fragment, extra_fragment) {
+ (Some(fragment), Some(_)) => {
+ // Shouldn't happen but who knows?
+ Ok((res, Some(fragment)))
+ }
+ (fragment, None) | (None, fragment) => Ok((res, fragment)),
+ },
+ }
+ }),
+ };
- let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| {
- // The resolved item did not match the disambiguator; give a better error than 'not found'
- let msg = format!("incompatible link kind for `{}`", path_str);
- report_diagnostic(cx, &msg, &item, &dox, &link_range, |diag, sp| {
- let note = format!(
- "this link resolved to {} {}, which is not {} {}",
- resolved.article(),
- resolved.descr(),
- specified.article(),
- specified.descr()
+ let len = candidates.iter().filter(|res| res.is_ok()).count();
+
+ if len == 0 {
+ resolution_failure(
+ self,
+ &item,
+ path_str,
+ disambiguator,
+ dox,
+ link_range,
+ candidates.into_iter().filter_map(|res| res.err()).collect(),
);
- diag.note(¬e);
- suggest_disambiguator(resolved, diag, path_str, &dox, sp, &link_range);
- });
- };
- if let Res::PrimTy(_) = res {
- match disambiguator {
- Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {
- item.attrs.links.push(ItemLink {
- link: ori_link,
- link_text: path_str.to_owned(),
- did: None,
- fragment,
- });
- }
- Some(other) => {
- report_mismatch(other, Disambiguator::Primitive);
- continue;
- }
+ // this could just be a normal link
+ return None;
}
- } else {
- debug!("intra-doc link to {} resolved to {:?}", path_str, res);
-
- // Disallow e.g. linking to enums with `struct@`
- if let Res::Def(kind, _) = res {
- debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
- match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) {
- | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
- // NOTE: this allows 'method' to mean both normal functions and associated functions
- // This can't cause ambiguity because both are in the same namespace.
- | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
- // These are namespaces; allow anything in the namespace to match
- | (_, Some(Disambiguator::Namespace(_)))
- // If no disambiguator given, allow anything
- | (_, None)
- // All of these are valid, so do nothing
- => {}
- (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
- (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
- report_mismatch(specified, Disambiguator::Kind(kind));
- continue;
- }
+
+ if len == 1 {
+ Some(candidates.into_iter().filter_map(|res| res.ok()).next().unwrap())
+ } else if len == 2 && is_derive_trait_collision(&candidates) {
+ Some(candidates.type_ns.unwrap())
+ } else {
+ if is_derive_trait_collision(&candidates) {
+ candidates.macro_ns = Err(ResolutionFailure::Dummy);
}
+ // If we're reporting an ambiguity, don't mention the namespaces that failed
+ let candidates = candidates.map(|candidate| candidate.ok().map(|(res, _)| res));
+ ambiguity_error(
+ self.cx,
+ &item,
+ path_str,
+ dox,
+ link_range,
+ candidates.present_items().collect(),
+ );
+ return None;
}
-
- // item can be non-local e.g. when using #[doc(primitive = "pointer")]
- if let Some((src_id, dst_id)) = res
- .opt_def_id()
- .and_then(|def_id| def_id.as_local())
- .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id)))
- {
- use rustc_hir::def_id::LOCAL_CRATE;
-
- let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id);
- let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id);
-
- if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src)
- && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst)
- {
- privacy_error(cx, &item, &path_str, &dox, link_range);
- continue;
+ }
+ Some(MacroNS) => {
+ match self.macro_resolve(path_str, base_node) {
+ Ok(res) => Some((res, extra_fragment)),
+ Err(mut kind) => {
+ // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible.
+ for &ns in &[TypeNS, ValueNS] {
+ if let Some(res) = self.check_full_res(
+ ns,
+ path_str,
+ base_node,
+ ¤t_item,
+ &extra_fragment,
+ ) {
+ kind = ResolutionFailure::WrongNamespace(res, MacroNS);
+ break;
+ }
+ }
+ resolution_failure(
+ self,
+ &item,
+ path_str,
+ disambiguator,
+ dox,
+ link_range,
+ smallvec![kind],
+ );
+ return None;
}
}
- let id = register_res(cx, res);
- item.attrs.links.push(ItemLink {
- link: ori_link,
- link_text,
- did: Some(id),
- fragment,
- });
}
}
-
- if item.is_mod() && !item.attrs.inner_docs {
- self.mod_ids.push(item.def_id);
- }
-
- if item.is_mod() {
- let ret = self.fold_item_recur(item);
-
- self.mod_ids.pop();
-
- ret
- } else {
- self.fold_item_recur(item)
- }
}
}
break;
}
};
- if let Some(res) = collector.check_full_res(
- TypeNS,
- ¤t,
- Some(*module_id),
- &None,
- &None,
- ) {
+ if let Some(res) =
+ collector.check_full_res(TypeNS, ¤t, *module_id, &None, &None)
+ {
failure = ResolutionFailure::NoAssocItem(res, Symbol::intern(current));
break;
}
use crate::clean::*;
use crate::core::DocContext;
use crate::fold::DocFolder;
-use crate::html::markdown::{find_testable_code, ErrorCodes, LangString};
+use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
use rustc_session::lint;
pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
pub(crate) found_tests: usize,
}
-impl Tests {
- pub(crate) fn new() -> Tests {
- Tests { found_tests: 0 }
- }
-}
-
impl crate::doctest::Tester for Tests {
- fn add_test(&mut self, _: String, _: LangString, _: usize) {
- self.found_tests += 1;
+ fn add_test(&mut self, _: String, config: LangString, _: usize) {
+ if config.rust && config.ignore == Ignore::None {
+ self.found_tests += 1;
+ }
}
}
}
};
- let mut tests = Tests::new();
+ let mut tests = Tests { found_tests: 0 };
find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
--- /dev/null
+// min-llvm-version: 11.0.0
+// compile-flags: -O
+// ignore-debug: the debug assertions get in the way
+#![crate_type = "lib"]
+
+// Make sure no bounds checks are emitted when slicing or indexing
+// with an index from `position()` or `rposition()`.
+
+// CHECK-LABEL: @position_slice_to_no_bounds_check
+#[no_mangle]
+pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().position(|b| *b == b'\\') {
+ &s[..idx]
+ } else {
+ s
+ }
+}
+
+// CHECK-LABEL: @position_slice_from_no_bounds_check
+#[no_mangle]
+pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().position(|b| *b == b'\\') {
+ &s[idx..]
+ } else {
+ s
+ }
+}
+
+// CHECK-LABEL: @position_index_no_bounds_check
+#[no_mangle]
+pub fn position_index_no_bounds_check(s: &[u8]) -> u8 {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().position(|b| *b == b'\\') {
+ s[idx]
+ } else {
+ 42
+ }
+}
+// CHECK-LABEL: @rposition_slice_to_no_bounds_check
+#[no_mangle]
+pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().rposition(|b| *b == b'\\') {
+ &s[..idx]
+ } else {
+ s
+ }
+}
+
+// CHECK-LABEL: @rposition_slice_from_no_bounds_check
+#[no_mangle]
+pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().rposition(|b| *b == b'\\') {
+ &s[idx..]
+ } else {
+ s
+ }
+}
+
+// CHECK-LABEL: @rposition_index_no_bounds_check
+#[no_mangle]
+pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 {
+ // CHECK-NOT: panic
+ // CHECK-NOT: slice_index_len_fail
+ if let Some(idx) = s.iter().rposition(|b| *b == b'\\') {
+ s[idx]
+ } else {
+ 42
+ }
+}
// + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar(<ZST>)) }
StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
_2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
+ StorageLive(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
_3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+ StorageLive(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
_4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
_0 = Eq(move _3, move _4); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11
+ StorageDead(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
+ StorageDead(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13
StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2
return; // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2
_7 = _2; // scope 1 at $DIR/inline-closure.rs:12:10: 12:11
(_5.0: i32) = move _6; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
(_5.1: i32) = move _7; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
+ StorageLive(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
_8 = move (_5.0: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
+ StorageLive(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
_9 = move (_5.1: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
_0 = _8; // scope 2 at $DIR/inline-closure.rs:11:22: 11:24
+ StorageDead(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
+ StorageDead(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
StorageDead(_7); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
StorageDead(_6); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
StorageDead(_5); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
_7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11
(_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
(_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
+ StorageLive(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
_8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
+ StorageLive(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
_9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
_0 = (*_8); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18
+ StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
+ StorageDead(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
_8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
(_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
+ StorageLive(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
_11 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
_9 = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
(_0.1: T) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24
StorageDead(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24
+ StorageDead(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
+-------------------------------------+------------+------------+------------+------------+
| File | Documented | Percentage | Examples | Percentage |
+-------------------------------------+------------+------------+------------+------------+
-| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 2 | 50.0% |
+| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 1 | 25.0% |
+-------------------------------------+------------+------------+------------+------------+
-| Total | 4 | 100.0% | 2 | 50.0% |
+| Total | 4 | 100.0% | 1 | 25.0% |
+-------------------------------------+------------+------------+------------+------------+
--- /dev/null
+// check-pass
+
+// regression test for #73264
+// should only give one error
+/// docs [label][with#anchor#error]
+//~^ WARNING multiple anchors
+pub struct S;
--- /dev/null
+warning: `with#anchor#error` contains multiple anchors
+ --> $DIR/intra-link-double-anchor.rs:5:18
+ |
+LL | /// docs [label][with#anchor#error]
+ | ^^^^^^^^^^^^^^^^^ contains invalid anchor
+ |
+ = note: `#[warn(broken_intra_doc_links)]` on by default
+
+warning: 1 warning emitted
+
--- /dev/null
+// check-pass
+
+#![deny(private_doc_tests)]
+
+mod foo {
+ /// private doc test
+ ///
+ /// ```ignore (used for testing ignored doc tests)
+ /// assert!(false);
+ /// ```
+ fn bar() {}
+}
--- /dev/null
+// aux-build:realcore.rs
+
+#![crate_name = "real_gimli"]
+#![feature(staged_api, extremely_unstable)]
+#![unstable(feature = "rustc_private", issue = "none")]
+
+extern crate realcore;
+
+#[unstable(feature = "rustc_private", issue = "none")]
+pub struct EndianSlice;
+
+#[unstable(feature = "rustc_private", issue = "none")]
+impl realcore::Deref for EndianSlice {}
--- /dev/null
+#![crate_name = "realcore"]
+#![feature(staged_api)]
+#![unstable(feature = "extremely_unstable", issue = "none")]
+
+#[unstable(feature = "extremely_unstable_foo", issue = "none")]
+pub struct Foo {}
+
+#[unstable(feature = "extremely_unstable_foo", issue = "none")]
+pub trait Join {}
+
+#[unstable(feature = "extremely_unstable_foo", issue = "none")]
+impl Join for Foo {}
+
+#[stable(feature = "faked_deref", since = "1.47.0")]
+pub trait Deref {}
--- /dev/null
+// ignore-tidy-linelength
+// aux-build:realcore.rs
+// aux-build:real_gimli.rs
+
+// Ensure unstably exported traits have their Implementors sections.
+
+#![crate_name = "foo"]
+#![feature(extremely_unstable_foo)]
+
+extern crate realcore;
+extern crate real_gimli;
+
+// issue #74672
+// @!has foo/trait.Deref.html '//*[@id="impl-Deref-for-EndianSlice"]//code' 'impl Deref for EndianSlice'
+pub use realcore::Deref;
+
+// @has foo/trait.Join.html '//*[@id="impl-Join-for-Foo"]//code' 'impl Join for Foo'
+pub use realcore::Join;
+++ /dev/null
-error[E0282]: type annotations needed
- --> $DIR/cannot-infer-const-args.rs:12:5
- |
-LL | foo();
- | ^^^
- |
- = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
+++ /dev/null
-error[E0282]: type annotations needed
- --> $DIR/cannot-infer-const-args.rs:12:5
- |
-LL | foo();
- | ^^^
- |
- = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
+++ /dev/null
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
-
-fn foo<const X: usize>() -> usize {
- 0
-}
-
-fn main() {
- foo(); //~ ERROR type annotations needed
-}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/cannot-infer-const-args.rs:12:5
+ |
+LL | foo();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `X`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/cannot-infer-const-args.rs:12:5
+ |
+LL | foo();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `X`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+fn foo<const X: usize>() -> usize {
+ 0
+}
+
+fn main() {
+ foo(); //~ ERROR type annotations needed
+}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/method-chain.rs:21:33
+ |
+LL | Foo.bar().bar().bar().bar().baz();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/method-chain.rs:21:33
+ |
+LL | Foo.bar().bar().bar().bar().baz();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+struct Foo;
+
+impl Foo {
+ fn bar(self) -> Foo {
+ Foo
+ }
+
+ fn baz<const N: usize>(self) -> Foo {
+ println!("baz: {}", N);
+ Foo
+ }
+}
+
+fn main() {
+ Foo.bar().bar().bar().bar().baz(); //~ ERROR type annotations needed
+}
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/uninferred-consts.rs:14:9
+ |
+LL | Foo.foo();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+error[E0282]: type annotations needed
+ --> $DIR/uninferred-consts.rs:14:9
+ |
+LL | Foo.foo();
+ | ^^^
+ |
+ = note: cannot infer the value of the const parameter `N`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+// Test that we emit an error if we cannot properly infer a constant.
+// revisions: full min
+
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+// taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893
+struct Foo;
+impl Foo {
+ fn foo<const N: usize>(self) {}
+}
+fn main() {
+ Foo.foo();
+ //~^ ERROR type annotations needed
+}
-error: generic parameters must not be used inside of non trivial constant values
+error: generic `Self` types are currently not permitted in anonymous constants
--> $DIR/issue-62504.rs:19:25
|
LL | ArrayHolder([0; Self::SIZE])
- | ^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
+ | ^^^^^^^^^^
|
- = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants
+note: not a concrete type
+ --> $DIR/issue-62504.rs:17:22
+ |
+LL | impl<const X: usize> ArrayHolder<X> {
+ | ^^^^^^^^^^^^^^
error: aborting due to previous error
pub const fn new() -> Self {
ArrayHolder([0; Self::SIZE])
//[full]~^ ERROR constant expression depends on a generic parameter
- //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+ //[min]~^^ ERROR generic `Self` types are currently
}
}
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {}
| ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T`
|
- = help: it is currently only allowed to use either `T` or `{ T }` as generic constants
+ = note: type parameters are currently not permitted in anonymous constants
error: generic parameters must not be used inside of non trivial constant values
--> $DIR/issue-64494.rs:19:38
LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {}
| ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T`
|
- = help: it is currently only allowed to use either `T` or `{ T }` as generic constants
+ = note: type parameters are currently not permitted in anonymous constants
error[E0119]: conflicting implementations of trait `MyTrait`:
--> $DIR/issue-64494.rs:19:1
LL | [0u8; mem::size_of::<Self::Associated>()];
| ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
|
- = help: it is currently only allowed to use either `Self` or `{ Self }` as generic constants
+ = note: type parameters are currently not permitted in anonymous constants
error: aborting due to previous error
--- /dev/null
+error: constant expression depends on a generic parameter
+ --> $DIR/issue-76701-ty-param-in-const.rs:6:21
+ |
+LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: constant expression depends on a generic parameter
+ --> $DIR/issue-76701-ty-param-in-const.rs:12:37
+ |
+LL | fn const_param<const N: usize>() -> [u8; N + 1] {
+ | ^^^^^^^^^^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+error: generic parameters must not be used inside of non trivial constant values
+ --> $DIR/issue-76701-ty-param-in-const.rs:6:46
+ |
+LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
+ | ^ non-trivial anonymous constants must not depend on the parameter `T`
+ |
+ = note: type parameters are currently not permitted in anonymous constants
+
+error: generic parameters must not be used inside of non trivial constant values
+ --> $DIR/issue-76701-ty-param-in-const.rs:12:42
+ |
+LL | fn const_param<const N: usize>() -> [u8; N + 1] {
+ | ^ non-trivial anonymous constants must not depend on the parameter `N`
+ |
+ = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(full, allow(incomplete_features))]
+#![cfg_attr(min, feature(min_const_generics))]
+
+fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] {
+ //[full]~^ ERROR constant expression depends on a generic parameter
+ //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+ todo!()
+}
+
+fn const_param<const N: usize>() -> [u8; N + 1] {
+ //[full]~^ ERROR constant expression depends on a generic parameter
+ //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values
+ todo!()
+}
+
+fn main() {}
--- /dev/null
+#![feature(min_const_generics)]
+
+trait Foo {
+ fn t1() -> [u8; std::mem::size_of::<Self>()]; //~ERROR generic parameters
+}
+
+struct Bar<T>(T);
+
+impl Bar<u8> {
+ fn t2() -> [u8; std::mem::size_of::<Self>()] { todo!() } // ok
+}
+
+impl<T> Bar<T> {
+ fn t3() -> [u8; std::mem::size_of::<Self>()] {} //~ERROR generic `Self`
+}
+
+trait Baz {
+ fn hey();
+}
+
+impl Baz for u16 {
+ fn hey() {
+ let _: [u8; std::mem::size_of::<Self>()]; // ok
+ }
+}
+
+fn main() {}
--- /dev/null
+error: generic parameters must not be used inside of non trivial constant values
+ --> $DIR/self-ty-in-const-1.rs:4:41
+ |
+LL | fn t1() -> [u8; std::mem::size_of::<Self>()];
+ | ^^^^ non-trivial anonymous constants must not depend on the parameter `Self`
+ |
+ = note: type parameters are currently not permitted in anonymous constants
+
+error: generic `Self` types are currently not permitted in anonymous constants
+ --> $DIR/self-ty-in-const-1.rs:14:41
+ |
+LL | fn t3() -> [u8; std::mem::size_of::<Self>()] {}
+ | ^^^^
+ |
+note: not a concrete type
+ --> $DIR/self-ty-in-const-1.rs:13:9
+ |
+LL | impl<T> Bar<T> {
+ | ^^^^^^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+#![feature(min_const_generics)]
+
+struct Bar<T>(T);
+
+trait Baz {
+ fn hey();
+}
+
+impl Baz for u16 {
+ fn hey() {
+ let _: [u8; std::mem::size_of::<Self>()]; // ok
+ }
+}
+
+impl<T> Baz for Bar<T> {
+ fn hey() {
+ let _: [u8; std::mem::size_of::<Self>()]; //~ERROR generic `Self`
+ }
+}
+
+fn main() {}
--- /dev/null
+error: generic `Self` types are currently not permitted in anonymous constants
+ --> $DIR/self-ty-in-const-2.rs:17:41
+ |
+LL | let _: [u8; std::mem::size_of::<Self>()];
+ | ^^^^
+ |
+note: not a concrete type
+ --> $DIR/self-ty-in-const-2.rs:15:17
+ |
+LL | impl<T> Baz for Bar<T> {
+ | ^^^^^^
+
+error: aborting due to previous error
+
LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U);
| ^ non-trivial anonymous constants must not depend on the parameter `T`
|
- = help: it is currently only allowed to use either `T` or `{ T }` as generic constants
+ = note: type parameters are currently not permitted in anonymous constants
error: constant values inside of type parameter defaults must not depend on generic parameters
--> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21
#![cfg_attr(min, feature(min_const_generics))]
trait SliceExt<T: Clone> {
- fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N>;
+ fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N>;
}
impl <T: Clone> SliceExt<T> for [T] {
- fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N> {
- ArrayWindows{ idx: 0, slice: &self }
+ fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N> {
+ ArrayWindowsExample{ idx: 0, slice: &self }
}
}
-struct ArrayWindows<'a, T, const N: usize> {
+struct ArrayWindowsExample<'a, T, const N: usize> {
slice: &'a [T],
idx: usize,
}
-impl <'a, T: Clone, const N: usize> Iterator for ArrayWindows<'a, T, N> {
+impl <'a, T: Clone, const N: usize> Iterator for ArrayWindowsExample<'a, T, N> {
type Item = [T; N];
fn next(&mut self) -> Option<Self::Item> {
// Note: this is unsound for some `T` and not meant as an example
fn main() {
let v: Vec<usize> = vec![0; 100];
- for array in v.as_slice().array_windows::<FOUR>() {
+ for array in v.as_slice().array_windows_example::<FOUR>() {
assert_eq!(array, [0, 0, 0, 0])
}
}
+++ /dev/null
-error[E0282]: type annotations needed
- --> $DIR/uninferred-consts.rs:14:5
- |
-LL | Foo.foo();
- | ^^^^^^^^^
- |
- = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
+++ /dev/null
-error[E0282]: type annotations needed
- --> $DIR/uninferred-consts.rs:14:5
- |
-LL | Foo.foo();
- | ^^^^^^^^^
- |
- = note: unable to infer the value of a const parameter
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0282`.
+++ /dev/null
-// Test that we emit an error if we cannot properly infer a constant.
-// revisions: full min
-
-#![cfg_attr(full, feature(const_generics))]
-#![cfg_attr(full, allow(incomplete_features))]
-#![cfg_attr(min, feature(min_const_generics))]
-
-// taken from https://github.com/rust-lang/rust/issues/70507#issuecomment-615268893
-struct Foo;
-impl Foo {
- fn foo<const N: usize>(self) {}
-}
-fn main() {
- Foo.foo();
- //~^ ERROR type annotations needed
-}
+++ /dev/null
-// run-pass
-
-#![feature(const_panic)]
-#![feature(duration_consts_2)]
-#![feature(div_duration)]
-#![feature(duration_saturating_ops)]
-
-use std::time::Duration;
-
-fn duration() {
- const ZERO : Duration = Duration::new(0, 0);
- assert_eq!(ZERO, Duration::from_secs(0));
-
- const ONE : Duration = Duration::new(0, 1);
- assert_eq!(ONE, Duration::from_nanos(1));
-
- const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1);
-
- const MAX_CHECKED_ADD_ZERO : Option<Duration> = MAX.checked_add(ZERO);
- assert_eq!(MAX_CHECKED_ADD_ZERO, Some(MAX));
-
- const MAX_CHECKED_ADD_ONE : Option<Duration> = MAX.checked_add(ONE);
- assert_eq!(MAX_CHECKED_ADD_ONE, None);
-
- const ONE_CHECKED_SUB_ONE : Option<Duration> = ONE.checked_sub(ONE);
- assert_eq!(ONE_CHECKED_SUB_ONE, Some(ZERO));
-
- const ZERO_CHECKED_SUB_ONE : Option<Duration> = ZERO.checked_sub(ONE);
- assert_eq!(ZERO_CHECKED_SUB_ONE, None);
-
- const ONE_CHECKED_MUL_ONE : Option<Duration> = ONE.checked_mul(1);
- assert_eq!(ONE_CHECKED_MUL_ONE, Some(ONE));
-
- const MAX_CHECKED_MUL_TWO : Option<Duration> = MAX.checked_mul(2);
- assert_eq!(MAX_CHECKED_MUL_TWO, None);
-
- const ONE_CHECKED_DIV_ONE : Option<Duration> = ONE.checked_div(1);
- assert_eq!(ONE_CHECKED_DIV_ONE, Some(ONE));
-
- const ONE_CHECKED_DIV_ZERO : Option<Duration> = ONE.checked_div(0);
- assert_eq!(ONE_CHECKED_DIV_ZERO, None);
-
- const MAX_AS_F32 : f32 = MAX.as_secs_f32();
- assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32);
-
- const MAX_AS_F64 : f64 = MAX.as_secs_f64();
- assert_eq!(MAX_AS_F64, 18446744073709552000.0_f64);
-
- const ONE_AS_F32 : f32 = ONE.div_duration_f32(ONE);
- assert_eq!(ONE_AS_F32, 1.0_f32);
-
- const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE);
- assert_eq!(ONE_AS_F64, 1.0_f64);
-
- const MAX_SATURATING_ADD_ONE : Duration = MAX.saturating_add(ONE);
- assert_eq!(MAX_SATURATING_ADD_ONE, MAX);
-
- const ZERO_SATURATING_SUB_ONE : Duration = ZERO.saturating_sub(ONE);
- assert_eq!(ZERO_SATURATING_SUB_ONE, ZERO);
-
- const MAX_SATURATING_MUL_TWO : Duration = MAX.saturating_mul(2);
- assert_eq!(MAX_SATURATING_MUL_TWO, MAX);
-}
-
-fn main() {
- duration();
-}
fn main() {
(0..13).collect<Vec<i32>>();
//~^ ERROR comparison operators cannot be chained
+ //~| HELP use `::<...>` instead
Vec<i32>::new();
//~^ ERROR comparison operators cannot be chained
+ //~| HELP use `::<...>` instead
(0..13).collect<Vec<i32>();
//~^ ERROR comparison operators cannot be chained
+ //~| HELP use `::<...>` instead
+ let x = std::collections::HashMap<i128, i128>::new(); //~ ERROR expected one of
+ //~^ HELP use `::<...>` instead
+ let x: () = 42; //~ ERROR mismatched types
+ let x = {
+ std::collections::HashMap<i128, i128>::new() //~ ERROR expected one of
+ //~^ HELP use `::<...>` instead
+ };
+ let x: () = 42; //~ ERROR mismatched types
+ let x = {
+ std::collections::HashMap<i128, i128>::new(); //~ ERROR expected one of
+ //~^ HELP use `::<...>` instead
+ let x: () = 42; //~ ERROR mismatched types
+ };
+ {
+ std::collections::HashMap<i128, i128>::new(1, 2); //~ ERROR expected one of
+ //~^ HELP use `::<...>` instead
+ let x: () = 32; //~ ERROR mismatched types
+ };
}
| ^^
error: comparison operators cannot be chained
- --> $DIR/issue-40396.rs:4:8
+ --> $DIR/issue-40396.rs:5:8
|
LL | Vec<i32>::new();
| ^ ^
| ^^
error: comparison operators cannot be chained
- --> $DIR/issue-40396.rs:6:20
+ --> $DIR/issue-40396.rs:8:20
|
LL | (0..13).collect<Vec<i32>();
| ^ ^
LL | (0..13).collect::<Vec<i32>();
| ^^
-error: aborting due to 3 previous errors
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,`
+ --> $DIR/issue-40396.rs:11:43
+ |
+LL | let x = std::collections::HashMap<i128, i128>::new();
+ | ^ expected one of 7 possible tokens
+ |
+help: use `::<...>` instead of `<...>` to specify type arguments
+ |
+LL | let x = std::collections::HashMap::<i128, i128>::new();
+ | ^^
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,`
+ --> $DIR/issue-40396.rs:15:39
+ |
+LL | std::collections::HashMap<i128, i128>::new()
+ | ^ expected one of 8 possible tokens
+ |
+help: use `::<...>` instead of `<...>` to specify type arguments
+ |
+LL | std::collections::HashMap::<i128, i128>::new()
+ | ^^
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,`
+ --> $DIR/issue-40396.rs:20:39
+ |
+LL | std::collections::HashMap<i128, i128>::new();
+ | ^ expected one of 8 possible tokens
+ |
+help: use `::<...>` instead of `<...>` to specify type arguments
+ |
+LL | std::collections::HashMap::<i128, i128>::new();
+ | ^^
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,`
+ --> $DIR/issue-40396.rs:25:39
+ |
+LL | std::collections::HashMap<i128, i128>::new(1, 2);
+ | ^ expected one of 8 possible tokens
+ |
+help: use `::<...>` instead of `<...>` to specify type arguments
+ |
+LL | std::collections::HashMap::<i128, i128>::new(1, 2);
+ | ^^
+
+error[E0308]: mismatched types
+ --> $DIR/issue-40396.rs:13:17
+ |
+LL | let x: () = 42;
+ | -- ^^ expected `()`, found integer
+ | |
+ | expected due to this
+
+error[E0308]: mismatched types
+ --> $DIR/issue-40396.rs:18:17
+ |
+LL | let x: () = 42;
+ | -- ^^ expected `()`, found integer
+ | |
+ | expected due to this
+
+error[E0308]: mismatched types
+ --> $DIR/issue-40396.rs:22:21
+ |
+LL | let x: () = 42;
+ | -- ^^ expected `()`, found integer
+ | |
+ | expected due to this
+
+error[E0308]: mismatched types
+ --> $DIR/issue-40396.rs:27:21
+ |
+LL | let x: () = 32;
+ | -- ^^ expected `()`, found integer
+ | |
+ | expected due to this
+
+error: aborting due to 11 previous errors
+For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// compile-flags: -Z teach
-
-struct Dog {
- name: String,
- age: u32,
-}
-
-fn main() {
- let d = Dog { name: "Rusty".to_string(), age: 8 };
-
- match d {
- Dog { age: x } => {}
- //~^ ERROR pattern does not mention field `name`
- }
-}
+++ /dev/null
-error[E0027]: pattern does not mention field `name`
- --> $DIR/E0027-teach.rs:12:9
- |
-LL | Dog { age: x } => {}
- | ^^^^^^^^^^^^^^ missing field `name`
- |
- = note: This error indicates that a pattern for a struct fails to specify a sub-pattern for every one of the struct's fields. Ensure that each field from the struct's definition is mentioned in the pattern, or use `..` to ignore unwanted fields.
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0027`.
let d = Dog { name: "Rusty".to_string(), age: 8 };
match d {
- Dog { age: x } => {}
- //~^ ERROR pattern does not mention field `name`
+ Dog { age: x } => {} //~ ERROR pattern does not mention field `name`
+ }
+ match d {
+ Dog {} => {} //~ ERROR pattern does not mention fields `name`, `age`
}
}
|
LL | Dog { age: x } => {}
| ^^^^^^^^^^^^^^ missing field `name`
+ |
+help: include the missing field in the pattern
+ |
+LL | Dog { age: x, name } => {}
+ | ^^^^^^
+help: if you don't care about this missing field, you can explicitely ignore it
+ |
+LL | Dog { age: x, .. } => {}
+ | ^^^^
+
+error[E0027]: pattern does not mention fields `name`, `age`
+ --> $DIR/E0027.rs:13:9
+ |
+LL | Dog {} => {}
+ | ^^^^^^ missing fields `name`, `age`
+ |
+help: include the missing fields in the pattern
+ |
+LL | Dog { name, age } => {}
+ | ^^^^^^^^^^^^^
+help: if you don't care about these missing fields, you can explicitely ignore them
+ |
+LL | Dog { .. } => {}
+ | ^^^^^^
-error: aborting due to previous error
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0027`.
+++ /dev/null
-#[doc(alias = "foo")] //~ ERROR: `#[doc(alias)]` is experimental
-pub struct Foo;
-
-fn main() {}
+++ /dev/null
-error[E0658]: `#[doc(alias)]` is experimental
- --> $DIR/feature-gate-doc_alias.rs:1:1
- |
-LL | #[doc(alias = "foo")]
- | ^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #50146 <https://github.com/rust-lang/rust/issues/50146> for more information
- = help: add `#![feature(doc_alias)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= help: if the trait `Foo` were object safe, you could return a boxed trait object
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: alternatively, create a new `enum` with a variant for each returned type
+ = help: you could instead create a new `enum` with a variant for each returned type
error[E0277]: cannot add `impl Foo` to `u32`
--> $DIR/equality.rs:24:11
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
= help: if the trait `NotObjectSafe` were object safe, you could return a boxed trait object
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: alternatively, create a new `enum` with a variant for each returned type
+ = help: you could instead create a new `enum` with a variant for each returned type
error[E0308]: mismatched types
--> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5
|
= note: to return `impl Trait`, all returned values must be of the same type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = help: you can instead return a boxed trait object using `Box<dyn ObjectSafe>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: alternatively, create a new `enum` with a variant for each returned type
+ = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn cat() -> Box<dyn ObjectSafe> {
+ | ^^^^^^^ ^
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL | return Box::new(A);
+LL | }
+LL | Box::new(B)
+ |
error: aborting due to 2 previous errors
LL | fn deref(&self) -> &Baz {
| ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
LL | self.as_ref()
- | ---- recursive call site
+ | ------------- recursive call site
|
= help: a `loop` may express intention better if this is on purpose
--- /dev/null
+// Verifies that inliner emits StorageLive & StorageDead when introducing
+// temporaries for arguments, so that they don't become part of the generator.
+// Regression test for #71793.
+//
+// check-pass
+// edition:2018
+// compile-args: -Zmir-opt-level=2
+
+#![crate_type = "lib"]
+
+pub async fn connect() {}
+
+pub async fn connect_many() {
+ Vec::<String>::new().first().ok_or("").unwrap();
+ connect().await;
+}
--- /dev/null
+use std::ops::Deref;
+
+struct NotCopy {
+ inner: bool
+}
+
+impl NotCopy {
+ fn inner_method(&self) {}
+}
+
+struct Foo {
+ first: NotCopy,
+ second: NotCopy
+}
+
+impl Deref for Foo {
+ type Target = NotCopy;
+ fn deref(&self) -> &NotCopy {
+ &self.second
+ }
+}
+
+fn use_field(val: Foo) {
+ let _val = val.first;
+ val.inner; //~ ERROR borrow of
+}
+
+fn use_method(val: Foo) {
+ let _val = val.first;
+ val.inner_method(); //~ ERROR borrow of
+}
+
+fn main() {}
--- /dev/null
+error[E0382]: borrow of partially moved value: `val`
+ --> $DIR/move-deref-coercion.rs:25:5
+ |
+LL | let _val = val.first;
+ | --------- value partially moved here
+LL | val.inner;
+ | ^^^^^^^^^ value borrowed here after partial move
+ |
+ = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait
+ = note: borrow occurs due to deref coercion to `NotCopy`
+note: deref defined here
+ --> $DIR/move-deref-coercion.rs:17:5
+ |
+LL | type Target = NotCopy;
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0382]: borrow of partially moved value: `val`
+ --> $DIR/move-deref-coercion.rs:30:5
+ |
+LL | let _val = val.first;
+ | --------- value partially moved here
+LL | val.inner_method();
+ | ^^^^^^^^^^^^^^^^^^ value borrowed here after partial move
+ |
+ = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait
+ = note: borrow occurs due to deref coercion to `NotCopy`
+note: deref defined here
+ --> $DIR/move-deref-coercion.rs:17:5
+ |
+LL | type Target = NotCopy;
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
error[E0382]: borrow of moved value: `arc_v`
- --> $DIR/no-capture-arc.rs:14:18
+ --> $DIR/no-capture-arc.rs:14:16
|
LL | let arc_v = Arc::new(v);
| ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
| ----- variable moved due to use in closure
...
LL | assert_eq!((*arc_v)[2], 3);
- | ^^^^^ value borrowed here after move
+ | ^^^^^^^^ value borrowed here after move
+ |
+ = note: borrow occurs due to deref coercion to `Vec<i32>`
+note: deref defined here
+ --> $SRC_DIR/alloc/src/sync.rs:LL:COL
+ |
+LL | type Target = T;
+ | ^^^^^^^^^^^^^^^^
error: aborting due to previous error
error[E0382]: borrow of moved value: `arc_v`
- --> $DIR/no-reuse-move-arc.rs:12:18
+ --> $DIR/no-reuse-move-arc.rs:12:16
|
LL | let arc_v = Arc::new(v);
| ----- move occurs because `arc_v` has type `Arc<Vec<i32>>`, which does not implement the `Copy` trait
| ----- variable moved due to use in closure
...
LL | assert_eq!((*arc_v)[2], 3);
- | ^^^^^ value borrowed here after move
+ | ^^^^^^^^ value borrowed here after move
+ |
+ = note: borrow occurs due to deref coercion to `Vec<i32>`
+note: deref defined here
+ --> $SRC_DIR/alloc/src/sync.rs:LL:COL
+ |
+LL | type Target = T;
+ | ^^^^^^^^^^^^^^^^
error: aborting due to previous error
+++ /dev/null
-// run-pass
-
-
-pub fn main() {
- let a: isize = 10;
- println!("{}", a);
- assert_eq!(a * (a - 1), 90);
-}
+++ /dev/null
-// run-pass
-
-
-pub fn main() {
- let i32_a: isize = 10;
- assert_eq!(i32_a, 10);
- assert_eq!(i32_a - 10, 0);
- assert_eq!(i32_a / 10, 1);
- assert_eq!(i32_a - 20, -10);
- assert_eq!(i32_a << 10, 10240);
- assert_eq!(i32_a << 16, 655360);
- assert_eq!(i32_a * 16, 160);
- assert_eq!(i32_a * i32_a * i32_a, 1000);
- assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000);
- assert_eq!(i32_a * i32_a / i32_a * i32_a, 100);
- assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640);
- let i32_b: isize = 0x10101010;
- assert_eq!(i32_b + 1 - 1, i32_b);
- assert_eq!(i32_b << 1, i32_b << 1);
- assert_eq!(i32_b >> 1, i32_b >> 1);
- assert_eq!(i32_b & i32_b << 1, 0);
- println!("{}", i32_b | i32_b << 1);
- assert_eq!(i32_b | i32_b << 1, 0x30303030);
-}
+++ /dev/null
-// run-pass
-
-
-
-pub fn main() {
- let i32_c: isize = 0x10101010;
- assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3),
- i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3));
-}
--- /dev/null
+#![crate_type="lib"]
+fn x<'a>(x: &mut 'a i32){} //~ ERROR lifetime must precede `mut`
+
+macro_rules! mac {
+ ($lt:lifetime) => {
+ fn w<$lt>(w: &mut $lt i32) {}
+ //~^ ERROR lifetime must precede `mut`
+ }
+}
+
+mac!('a);
+
+// avoid false positives
+fn y<'a>(y: &mut 'a + Send) {
+ //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a`
+ //~| WARNING trait objects without an explicit `dyn` are deprecated
+ //~| ERROR at least one trait is required for an object type
+ let z = y as &mut 'a + Send;
+ //~^ ERROR expected value, found trait `Send`
+ //~| WARNING trait objects without an explicit `dyn` are deprecated
+}
--- /dev/null
+error: lifetime must precede `mut`
+ --> $DIR/issue-73568-lifetime-after-mut.rs:2:13
+ |
+LL | fn x<'a>(x: &mut 'a i32){}
+ | ^^^^^^^ help: place the lifetime before `mut`: `&'a mut`
+
+error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a`
+ --> $DIR/issue-73568-lifetime-after-mut.rs:14:13
+ |
+LL | fn y<'a>(y: &mut 'a + Send) {
+ | ^^^^^^^^^^^^^^ help: try adding parentheses: `&mut ('a + Send)`
+
+error: lifetime must precede `mut`
+ --> $DIR/issue-73568-lifetime-after-mut.rs:6:22
+ |
+LL | fn w<$lt>(w: &mut $lt i32) {}
+ | ^^^^^^^^ help: place the lifetime before `mut`: `&$lt mut`
+...
+LL | mac!('a);
+ | --------- in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0423]: expected value, found trait `Send`
+ --> $DIR/issue-73568-lifetime-after-mut.rs:18:28
+ |
+LL | let z = y as &mut 'a + Send;
+ | ^^^^ not a value
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-73568-lifetime-after-mut.rs:14:18
+ |
+LL | fn y<'a>(y: &mut 'a + Send) {
+ | ^^ help: use `dyn`: `dyn 'a`
+ |
+ = note: `#[warn(bare_trait_objects)]` on by default
+
+warning: trait objects without an explicit `dyn` are deprecated
+ --> $DIR/issue-73568-lifetime-after-mut.rs:18:23
+ |
+LL | let z = y as &mut 'a + Send;
+ | ^^ help: use `dyn`: `dyn 'a`
+
+error[E0224]: at least one trait is required for an object type
+ --> $DIR/issue-73568-lifetime-after-mut.rs:14:18
+ |
+LL | fn y<'a>(y: &mut 'a + Send) {
+ | ^^
+
+error: aborting due to 5 previous errors; 2 warnings emitted
+
+Some errors have detailed explanations: E0178, E0224, E0423.
+For more information about an error, try `rustc --explain E0178`.
if false {
return 0i32;
}
- 1u32
- //~^ ERROR mismatched types
+ 1u32 //~ ERROR mismatched types
}
fn bar() -> impl std::fmt::Display {
if false {
return 0i32;
} else {
- return 1u32;
- //~^ ERROR mismatched types
+ return 1u32; //~ ERROR mismatched types
}
}
if false {
return 0i32;
} else {
- 1u32
- //~^ ERROR mismatched types
+ 1u32 //~ ERROR mismatched types
}
}
if false {
0i32
} else {
- 1u32
- //~^ ERROR `if` and `else` have incompatible types
+ 1u32 //~ ERROR `if` and `else` have incompatible types
}
}
fn bat() -> impl std::fmt::Display {
match 13 {
0 => return 0i32,
- _ => 1u32,
- //~^ ERROR mismatched types
+ _ => 1u32, //~ ERROR mismatched types
}
}
fn can() -> impl std::fmt::Display {
- match 13 {
- //~^ ERROR mismatched types
+ match 13 { //~ ERROR mismatched types
0 => return 0i32,
1 => 1u32,
_ => 2u32,
}
fn cat() -> impl std::fmt::Display {
+ match 13 {
+ 0 => {
+ return 0i32;
+ }
+ _ => {
+ 1u32 //~ ERROR mismatched types
+ }
+ }
+}
+
+fn dog() -> impl std::fmt::Display {
+ match 13 {
+ 0 => 0i32,
+ 1 => 1u32, //~ ERROR `match` arms have incompatible types
+ _ => 2u32,
+ }
+}
+
+fn hat() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object
match 13 {
0 => {
return 0i32;
}
_ => {
1u32
- //~^ ERROR mismatched types
}
}
}
+fn pug() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object
+ match 13 {
+ 0 => 0i32,
+ 1 => 1u32, //~ ERROR `match` arms have incompatible types
+ _ => 2u32,
+ }
+}
+
+fn man() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object
+ if false {
+ 0i32
+ } else {
+ 1u32 //~ ERROR `if` and `else` have incompatible types
+ }
+}
+
+fn apt() -> impl std::fmt::Display {
+ if let Some(42) = Some(42) {
+ 0i32
+ } else {
+ 1u32 //~ ERROR `if` and `else` have incompatible types
+ }
+}
+
fn main() {}
|
= note: to return `impl Trait`, all returned values must be of the same type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: alternatively, create a new `enum` with a variant for each returned type
+ = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn foo() -> Box<dyn std::fmt::Display> {
+ | ^^^^^^^ ^
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL | return Box::new(0i32);
+LL | }
+LL | Box::new(1u32)
+ |
error[E0308]: mismatched types
- --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16
|
LL | fn bar() -> impl std::fmt::Display {
| ---------------------- expected because this return type...
|
= note: to return `impl Trait`, all returned values must be of the same type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: alternatively, create a new `enum` with a variant for each returned type
+ = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn bar() -> Box<dyn std::fmt::Display> {
+ | ^^^^^^^ ^
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL | return Box::new(0i32);
+LL | } else {
+LL | return Box::new(1u32);
+ |
error[E0308]: mismatched types
- --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9
|
LL | fn baz() -> impl std::fmt::Display {
| ---------------------- expected because this return type...
|
= note: to return `impl Trait`, all returned values must be of the same type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: alternatively, create a new `enum` with a variant for each returned type
+ = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn baz() -> Box<dyn std::fmt::Display> {
+ | ^^^^^^^ ^
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL | return Box::new(0i32);
+LL | } else {
+LL | Box::new(1u32)
+ |
error[E0308]: `if` and `else` have incompatible types
- --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9
|
LL | / if false {
LL | | 0i32
LL | | } else {
LL | | 1u32
| | ^^^^ expected `i32`, found `u32`
-LL | |
LL | | }
| |_____- `if` and `else` have incompatible types
+ |
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn qux() -> Box<dyn std::fmt::Display> {
+ | ^^^^^^^ ^
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL | Box::new(0i32)
+LL | } else {
+LL | Box::new(1u32)
+ |
error[E0308]: mismatched types
- --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:39:14
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14
|
LL | fn bat() -> impl std::fmt::Display {
| ---------------------- expected because this return type...
|
= note: to return `impl Trait`, all returned values must be of the same type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: alternatively, create a new `enum` with a variant for each returned type
+ = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn bat() -> Box<dyn std::fmt::Display> {
+ | ^^^^^^^ ^
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL | 0 => return Box::new(0i32),
+LL | _ => Box::new(1u32),
+ |
error[E0308]: mismatched types
- --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5
|
LL | fn can() -> impl std::fmt::Display {
| ---------------------- expected because this return type...
LL | / match 13 {
-LL | |
LL | | 0 => return 0i32,
| | ---- ...is found to be `i32` here
LL | | 1 => 1u32,
|
= note: to return `impl Trait`, all returned values must be of the same type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: alternatively, create a new `enum` with a variant for each returned type
+ = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn can() -> Box<dyn std::fmt::Display> {
+ | ^^^^^^^ ^
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL | Box::new(match 13 {
+LL | 0 => return Box::new(0i32),
+LL | 1 => 1u32,
+LL | _ => 2u32,
+LL | })
+ |
error[E0308]: mismatched types
- --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13
|
LL | fn cat() -> impl std::fmt::Display {
| ---------------------- expected because this return type...
|
= note: to return `impl Trait`, all returned values must be of the same type
= note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
- = help: you can instead return a boxed trait object using `Box<dyn std::fmt::Display>`
= note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
- = help: alternatively, create a new `enum` with a variant for each returned type
+ = help: you could instead create a new `enum` with a variant for each returned type
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn cat() -> Box<dyn std::fmt::Display> {
+ | ^^^^^^^ ^
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL | return Box::new(0i32);
+LL | }
+LL | _ => {
+LL | Box::new(1u32)
+ |
+
+error[E0308]: `match` arms have incompatible types
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14
+ |
+LL | / match 13 {
+LL | | 0 => 0i32,
+ | | ---- this is found to be of type `i32`
+LL | | 1 => 1u32,
+ | | ^^^^ expected `i32`, found `u32`
+LL | | _ => 2u32,
+LL | | }
+ | |_____- `match` arms have incompatible types
+ |
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn dog() -> Box<dyn std::fmt::Display> {
+ | ^^^^^^^ ^
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL | 0 => Box::new(0i32),
+LL | 1 => Box::new(1u32),
+ |
+
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9
+ |
+LL | / if let Some(42) = Some(42) {
+LL | | 0i32
+ | | ---- expected because of this
+LL | | } else {
+LL | | 1u32
+ | | ^^^^ expected `i32`, found `u32`
+LL | | }
+ | |_____- `if` and `else` have incompatible types
+ |
+help: you could change the return type to be a boxed trait object
+ |
+LL | fn apt() -> Box<dyn std::fmt::Display> {
+ | ^^^^^^^ ^
+help: if you change the return type to expect trait objects, box the returned expressions
+ |
+LL | Box::new(0i32)
+LL | } else {
+LL | Box::new(1u32)
+ |
+
+error[E0746]: return type cannot have an unboxed trait object
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13
+ |
+LL | fn hat() -> dyn std::fmt::Display {
+ | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+ = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
+ = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+ = note: you can create a new `enum` with a variant for each returned type
+help: return a boxed trait object instead
+ |
+LL | fn hat() -> Box<dyn std::fmt::Display> {
+LL | match 13 {
+LL | 0 => {
+LL | return Box::new(0i32);
+LL | }
+LL | _ => {
+ ...
+
+error[E0308]: `match` arms have incompatible types
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14
+ |
+LL | / match 13 {
+LL | | 0 => 0i32,
+ | | ---- this is found to be of type `i32`
+LL | | 1 => 1u32,
+ | | ^^^^ expected `i32`, found `u32`
+LL | | _ => 2u32,
+LL | | }
+ | |_____- `match` arms have incompatible types
+
+error[E0746]: return type cannot have an unboxed trait object
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13
+ |
+LL | fn pug() -> dyn std::fmt::Display {
+ | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+ = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
+ = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+ = note: you can create a new `enum` with a variant for each returned type
+help: return a boxed trait object instead
+ |
+LL | fn pug() -> Box<dyn std::fmt::Display> {
+LL | match 13 {
+LL | 0 => Box::new(0i32),
+LL | 1 => Box::new(1u32),
+LL | _ => Box::new(2u32),
+ |
+
+error[E0308]: `if` and `else` have incompatible types
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9
+ |
+LL | / if false {
+LL | | 0i32
+ | | ---- expected because of this
+LL | | } else {
+LL | | 1u32
+ | | ^^^^ expected `i32`, found `u32`
+LL | | }
+ | |_____- `if` and `else` have incompatible types
+
+error[E0746]: return type cannot have an unboxed trait object
+ --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13
+ |
+LL | fn man() -> dyn std::fmt::Display {
+ | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+ |
+ = note: for information on trait objects, see <https://doc.rust-lang.org/book/ch17-02-trait-objects.html#using-trait-objects-that-allow-for-values-of-different-types>
+ = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type
+ = note: for information on `impl Trait`, see <https://doc.rust-lang.org/book/ch10-02-traits.html#returning-types-that-implement-traits>
+ = note: you can create a new `enum` with a variant for each returned type
+help: return a boxed trait object instead
+ |
+LL | fn man() -> Box<dyn std::fmt::Display> {
+LL | if false {
+LL | Box::new(0i32)
+LL | } else {
+LL | Box::new(1u32)
+ |
-error: aborting due to 7 previous errors
+error: aborting due to 14 previous errors
-For more information about this error, try `rustc --explain E0308`.
+Some errors have detailed explanations: E0308, E0746.
+For more information about an error, try `rustc --explain E0308`.
+++ /dev/null
-// run-pass
-
-pub fn main() {
- let a: String = "this \
-is a test".to_string();
- let b: String =
- "this \
- is \
- another \
- test".to_string();
- assert_eq!(a, "this is a test".to_string());
- assert_eq!(b, "this is another test".to_string());
-}
+++ /dev/null
-// run-pass
-
-fn main() {
- let x = "\\\\\
- ";
- assert_eq!(x, r"\\"); // extraneous whitespace stripped
-}
|
LL | let Foo { #[cfg(any())] present: () } = foo;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `present`
+ |
+help: include the missing field in the pattern
+ |
+LL | let Foo { present } = foo;
+ | ^^^^^^^^^^^
+help: if you don't care about this missing field, you can explicitely ignore it
+ |
+LL | let Foo { .. } = foo;
+ | ^^^^^^
error[E0026]: struct `Foo` does not have a field named `absent`
--> $DIR/struct-field-cfg.rs:16:42
|
LL | let A { x, y } = self.d;
| ^^^^^^^^^^ missing fields `b`, `c`
+ |
+help: include the missing fields in the pattern
+ |
+LL | let A { x, y, b, c } = self.d;
+ | ^^^^^^
+help: if you don't care about these missing fields, you can explicitely ignore them
+ |
+LL | let A { x, y, .. } = self.d;
+ | ^^^^
error: aborting due to 3 previous errors
--- /dev/null
+// run-rustfix
+
+#[allow(unused)]
+use std::fmt::Debug;
+// Rustfix should add this, or use `std::fmt::Debug` instead.
+
+#[allow(dead_code)]
+struct ConstrainedStruct<X: Copy> {
+ x: X
+}
+
+#[allow(dead_code)]
+trait InsufficientlyConstrainedGeneric<X=()> where X: Copy {
+ fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+ //~^ ERROR the trait bound `X: Copy` is not satisfied
+ ConstrainedStruct { x }
+ }
+}
+
+pub fn main() { }
--- /dev/null
+// run-rustfix
+
+#[allow(unused)]
+use std::fmt::Debug;
+// Rustfix should add this, or use `std::fmt::Debug` instead.
+
+#[allow(dead_code)]
+struct ConstrainedStruct<X: Copy> {
+ x: X
+}
+
+#[allow(dead_code)]
+trait InsufficientlyConstrainedGeneric<X=()> {
+ fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+ //~^ ERROR the trait bound `X: Copy` is not satisfied
+ ConstrainedStruct { x }
+ }
+}
+
+pub fn main() { }
--- /dev/null
+error[E0277]: the trait bound `X: Copy` is not satisfied
+ --> $DIR/trait-impl-bound-suggestions.rs:14:52
+ |
+LL | struct ConstrainedStruct<X: Copy> {
+ | ---- required by this bound in `ConstrainedStruct`
+...
+LL | fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+ | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `X`
+ |
+help: consider further restricting type parameter `X`
+ |
+LL | trait InsufficientlyConstrainedGeneric<X=()> where X: Copy {
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
|
help: consider further restricting type parameter `T`
|
-LL | trait Base<T = String>: Super<T>, T: Copy { }
- | ^^^^^^^^^
+LL | trait Base<T = String>: Super<T> where T: Copy { }
+ | ^^^^^^^^^^^^^
error[E0277]: cannot add `u8` to `i32`
--> $DIR/type-check-defaults.rs:24:66
{
let y = Y { a: S };
}
- assert_eq!(CHECK, 2); // 2, dtor of Y is called
+ assert_eq!(CHECK, 2); // 2, Y has no dtor
+ {
+ let u2 = U { a: 1 };
+ std::mem::forget(u2);
+ }
+ assert_eq!(CHECK, 2); // 2, dtor of U *not* called for u2
}
}
--- /dev/null
+//! Test the behavior of moving out of non-`Copy` union fields.
+//! Avoid types that `Drop`, we want to focus on moving.
+#![feature(untagged_unions)]
+
+use std::cell::RefCell;
+
+fn move_out<T>(x: T) {}
+
+union U1 {
+ f1_nocopy: RefCell<i32>,
+ f2_nocopy: RefCell<i32>,
+ f3_copy: i32,
+}
+
+union U2 {
+ f1_nocopy: RefCell<i32>,
+}
+impl Drop for U2 {
+ fn drop(&mut self) {}
+}
+
+fn test1(x: U1) {
+ // Moving out of a nocopy field prevents accessing other nocopy field.
+ unsafe {
+ move_out(x.f1_nocopy);
+ move_out(x.f2_nocopy); //~ ERROR use of moved value: `x`
+ }
+}
+
+fn test2(x: U1) {
+ // "Moving" out of copy field doesn't prevent later field accesses.
+ unsafe {
+ move_out(x.f3_copy);
+ move_out(x.f2_nocopy); // no error
+ }
+}
+
+fn test3(x: U1) {
+ // Moving out of a nocopy field prevents accessing other copy field.
+ unsafe {
+ move_out(x.f2_nocopy);
+ move_out(x.f3_copy); //~ ERROR use of moved value: `x`
+ }
+}
+
+fn test4(x: U2) {
+ // Cannot move out of union that implements `Drop`.
+ unsafe {
+ move_out(x.f1_nocopy); //~ ERROR cannot move out of type `U2`, which implements the `Drop`
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0382]: use of moved value: `x`
+ --> $DIR/union-move.rs:26:18
+ |
+LL | fn test1(x: U1) {
+ | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL | move_out(x.f1_nocopy);
+ | ----------- value moved here
+LL | move_out(x.f2_nocopy);
+ | ^^^^^^^^^^^ value used here after move
+
+error[E0382]: use of moved value: `x`
+ --> $DIR/union-move.rs:42:18
+ |
+LL | fn test3(x: U1) {
+ | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait
+...
+LL | move_out(x.f2_nocopy);
+ | ----------- value moved here
+LL | move_out(x.f3_copy);
+ | ^^^^^^^^^ value used here after move
+
+error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
+ --> $DIR/union-move.rs:49:18
+ |
+LL | move_out(x.f1_nocopy);
+ | ^^^^^^^^^^^
+ | |
+ | cannot move out of here
+ | move occurs because `x.f1_nocopy` has type `RefCell<i32>`, which does not implement the `Copy` trait
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0382, E0509.
+For more information about an error, try `rustc --explain E0382`.
-Subproject commit 875e0123259b0b6299903fe4aea0a12ecde9324f
+Subproject commit 8777a6b1e8834899f51b7e09cc9b8d85b2417110
pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
-pub const SLICE_ITER: [&str; 3] = ["core", "slice", "Iter"];
+pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
pub const STD_CONVERT_IDENTITY: [&str; 3] = ["std", "convert", "identity"];
if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) {
entry.1.contains(&link)
} else {
+ // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page
+ //
+ // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path
+ // calculated in `check` function is outside `build/<triple>/doc` dir.
+ // So the `strip_prefix` method just returns the old absolute broken path.
+ if file.ends_with("std/primitive.slice.html") {
+ if link.ends_with("primitive.slice.html") {
+ return true;
+ }
+ }
false
}
}
--- /dev/null
+[package]
+name = "lint-docs"
+version = "0.1.0"
+authors = ["The Rust Project Developers"]
+edition = "2018"
+description = "A script to extract the lint documentation for the rustc book."
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+serde_json = "1.0.57"
+tempfile = "3.1.0"
+walkdir = "2.3.1"
--- /dev/null
+use crate::Lint;
+use std::collections::{BTreeMap, BTreeSet};
+use std::error::Error;
+use std::fmt::Write;
+use std::fs;
+use std::path::Path;
+use std::process::Command;
+
+static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
+ ("unused", "Lints that detect things being declared but not used, or excess syntax"),
+ ("rustdoc", "Rustdoc-specific lints"),
+ ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"),
+ ("nonstandard-style", "Violation of standard naming conventions"),
+ ("future-incompatible", "Lints that detect code that has future-compatibility problems"),
+ ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
+];
+
+/// Updates the documentation of lint groups.
+pub(crate) fn generate_group_docs(
+ lints: &[Lint],
+ rustc_path: &Path,
+ out_path: &Path,
+) -> Result<(), Box<dyn Error>> {
+ let groups = collect_groups(rustc_path)?;
+ let groups_path = out_path.join("groups.md");
+ let contents = fs::read_to_string(&groups_path)
+ .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
+ let new_contents = contents.replace("{{groups-table}}", &make_groups_table(lints, &groups)?);
+ // Delete the output because rustbuild uses hard links in its copies.
+ let _ = fs::remove_file(&groups_path);
+ fs::write(&groups_path, new_contents)
+ .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
+ Ok(())
+}
+
+type LintGroups = BTreeMap<String, BTreeSet<String>>;
+
+/// Collects the group names from rustc.
+fn collect_groups(rustc: &Path) -> Result<LintGroups, Box<dyn Error>> {
+ let mut result = BTreeMap::new();
+ let mut cmd = Command::new(rustc);
+ cmd.arg("-Whelp");
+ let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
+ if !output.status.success() {
+ return Err(format!(
+ "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
+ output.status,
+ std::str::from_utf8(&output.stderr).unwrap(),
+ std::str::from_utf8(&output.stdout).unwrap(),
+ )
+ .into());
+ }
+ let stdout = std::str::from_utf8(&output.stdout).unwrap();
+ let lines = stdout.lines();
+ let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
+ let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
+ for line in table_start {
+ if line.is_empty() {
+ break;
+ }
+ let mut parts = line.trim().splitn(2, ' ');
+ let name = parts.next().expect("name in group");
+ if name == "warnings" {
+ // This is special.
+ continue;
+ }
+ let lints =
+ parts.next().ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
+ let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
+ assert!(result.insert(name.to_string(), lints).is_none());
+ }
+ if result.is_empty() {
+ return Err(
+ format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
+ );
+ }
+ Ok(result)
+}
+
+fn make_groups_table(lints: &[Lint], groups: &LintGroups) -> Result<String, Box<dyn Error>> {
+ let mut result = String::new();
+ let mut to_link = Vec::new();
+ result.push_str("| Group | Description | Lints |\n");
+ result.push_str("|-------|-------------|-------|\n");
+ result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n");
+ for (group_name, group_lints) in groups {
+ let description = GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name)
+ .ok_or_else(|| format!("lint group `{}` does not have a description, please update the GROUP_DESCRIPTIONS list", group_name))?
+ .1;
+ to_link.extend(group_lints);
+ let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
+ write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")).unwrap();
+ }
+ result.push('\n');
+ result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
+ for lint_name in to_link {
+ let lint_def =
+ lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| {
+ format!(
+ "`rustc -W help` defined lint `{}` but that lint does not appear to exist",
+ lint_name
+ )
+ })?;
+ write!(
+ result,
+ "[{}]: listing/{}#{}\n",
+ lint_name,
+ lint_def.level.doc_filename(),
+ lint_name
+ )
+ .unwrap();
+ }
+ Ok(result)
+}
--- /dev/null
+use std::error::Error;
+use std::fmt::Write;
+use std::fs;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+use walkdir::WalkDir;
+
+mod groups;
+
+struct Lint {
+ name: String,
+ doc: Vec<String>,
+ level: Level,
+ path: PathBuf,
+ lineno: usize,
+}
+
+impl Lint {
+ fn doc_contains(&self, text: &str) -> bool {
+ self.doc.iter().any(|line| line.contains(text))
+ }
+
+ fn is_ignored(&self) -> bool {
+ self.doc
+ .iter()
+ .filter(|line| line.starts_with("```rust"))
+ .all(|line| line.contains(",ignore"))
+ }
+}
+
+#[derive(Clone, Copy, PartialEq)]
+enum Level {
+ Allow,
+ Warn,
+ Deny,
+}
+
+impl Level {
+ fn doc_filename(&self) -> &str {
+ match self {
+ Level::Allow => "allowed-by-default.md",
+ Level::Warn => "warn-by-default.md",
+ Level::Deny => "deny-by-default.md",
+ }
+ }
+}
+
+/// Collects all lints, and writes the markdown documentation at the given directory.
+pub fn extract_lint_docs(
+ src_path: &Path,
+ out_path: &Path,
+ rustc_path: &Path,
+ verbose: bool,
+) -> Result<(), Box<dyn Error>> {
+ let mut lints = gather_lints(src_path)?;
+ for lint in &mut lints {
+ generate_output_example(lint, rustc_path, verbose).map_err(|e| {
+ format!(
+ "failed to test example in lint docs for `{}` in {}:{}: {}",
+ lint.name,
+ lint.path.display(),
+ lint.lineno,
+ e
+ )
+ })?;
+ }
+ save_lints_markdown(&lints, &out_path.join("listing"))?;
+ groups::generate_group_docs(&lints, rustc_path, out_path)?;
+ Ok(())
+}
+
+/// Collects all lints from all files in the given directory.
+fn gather_lints(src_path: &Path) -> Result<Vec<Lint>, Box<dyn Error>> {
+ let mut lints = Vec::new();
+ for entry in WalkDir::new(src_path).into_iter().filter_map(|e| e.ok()) {
+ if !entry.path().extension().map_or(false, |ext| ext == "rs") {
+ continue;
+ }
+ lints.extend(lints_from_file(entry.path())?);
+ }
+ if lints.is_empty() {
+ return Err("no lints were found!".into());
+ }
+ Ok(lints)
+}
+
+/// Collects all lints from the given file.
+fn lints_from_file(path: &Path) -> Result<Vec<Lint>, Box<dyn Error>> {
+ let mut lints = Vec::new();
+ let contents = fs::read_to_string(path)
+ .map_err(|e| format!("could not read {}: {}", path.display(), e))?;
+ let mut lines = contents.lines().enumerate();
+ loop {
+ // Find a lint declaration.
+ let lint_start = loop {
+ match lines.next() {
+ Some((lineno, line)) => {
+ if line.trim().starts_with("declare_lint!") {
+ break lineno + 1;
+ }
+ }
+ None => return Ok(lints),
+ }
+ };
+ // Read the lint.
+ let mut doc_lines = Vec::new();
+ let (doc, name) = loop {
+ match lines.next() {
+ Some((lineno, line)) => {
+ let line = line.trim();
+ if line.starts_with("/// ") {
+ doc_lines.push(line.trim()[4..].to_string());
+ } else if line.starts_with("///") {
+ doc_lines.push("".to_string());
+ } else if line.starts_with("// ") {
+ // Ignore comments.
+ continue;
+ } else {
+ let name = lint_name(line).map_err(|e| {
+ format!(
+ "could not determine lint name in {}:{}: {}, line was `{}`",
+ path.display(),
+ lineno,
+ e,
+ line
+ )
+ })?;
+ if doc_lines.is_empty() {
+ return Err(format!(
+ "did not find doc lines for lint `{}` in {}",
+ name,
+ path.display()
+ )
+ .into());
+ }
+ break (doc_lines, name);
+ }
+ }
+ None => {
+ return Err(format!(
+ "unexpected EOF for lint definition at {}:{}",
+ path.display(),
+ lint_start
+ )
+ .into());
+ }
+ }
+ };
+ // These lints are specifically undocumented. This should be reserved
+ // for internal rustc-lints only.
+ if name == "deprecated_in_future" {
+ continue;
+ }
+ // Read the level.
+ let level = loop {
+ match lines.next() {
+ // Ignore comments.
+ Some((_, line)) if line.trim().starts_with("// ") => {}
+ Some((lineno, line)) => match line.trim() {
+ "Allow," => break Level::Allow,
+ "Warn," => break Level::Warn,
+ "Deny," => break Level::Deny,
+ _ => {
+ return Err(format!(
+ "unexpected lint level `{}` in {}:{}",
+ line,
+ path.display(),
+ lineno
+ )
+ .into());
+ }
+ },
+ None => {
+ return Err(format!(
+ "expected lint level in {}:{}, got EOF",
+ path.display(),
+ lint_start
+ )
+ .into());
+ }
+ }
+ };
+ // The rest of the lint definition is ignored.
+ assert!(!doc.is_empty());
+ lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start });
+ }
+}
+
+/// Extracts the lint name (removing the visibility modifier, and checking validity).
+fn lint_name(line: &str) -> Result<String, &'static str> {
+ // Skip over any potential `pub` visibility.
+ match line.trim().split(' ').next_back() {
+ Some(name) => {
+ if !name.ends_with(',') {
+ return Err("lint name should end with comma");
+ }
+ let name = &name[..name.len() - 1];
+ if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() {
+ return Err("lint name did not have expected format");
+ }
+ Ok(name.to_lowercase().to_string())
+ }
+ None => Err("could not find lint name"),
+ }
+}
+
+/// Mutates the lint definition to replace the `{{produces}}` marker with the
+/// actual output from the compiler.
+fn generate_output_example(
+ lint: &mut Lint,
+ rustc_path: &Path,
+ verbose: bool,
+) -> Result<(), Box<dyn Error>> {
+ // Explicit list of lints that are allowed to not have an example. Please
+ // try to avoid adding to this list.
+ if matches!(
+ lint.name.as_str(),
+ "unused_features" // broken lint
+ | "unstable_features" // deprecated
+ ) {
+ return Ok(());
+ }
+ if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") {
+ // Rustdoc lints are documented in the rustdoc book, don't check these.
+ return Ok(());
+ }
+ check_style(lint)?;
+ // Unfortunately some lints have extra requirements that this simple test
+ // setup can't handle (like extern crates). An alternative is to use a
+ // separate test suite, and use an include mechanism such as mdbook's
+ // `{{#rustdoc_include}}`.
+ if !lint.is_ignored() {
+ replace_produces(lint, rustc_path, verbose)?;
+ }
+ Ok(())
+}
+
+/// Checks the doc style of the lint.
+fn check_style(lint: &Lint) -> Result<(), Box<dyn Error>> {
+ for &expected in &["### Example", "### Explanation", "{{produces}}"] {
+ if expected == "{{produces}}" && lint.is_ignored() {
+ continue;
+ }
+ if !lint.doc_contains(expected) {
+ return Err(format!("lint docs should contain the line `{}`", expected).into());
+ }
+ }
+ if let Some(first) = lint.doc.first() {
+ if !first.starts_with(&format!("The `{}` lint", lint.name)) {
+ return Err(format!(
+ "lint docs should start with the text \"The `{}` lint\" to introduce the lint",
+ lint.name
+ )
+ .into());
+ }
+ }
+ Ok(())
+}
+
+/// Mutates the lint docs to replace the `{{produces}}` marker with the actual
+/// output from the compiler.
+fn replace_produces(
+ lint: &mut Lint,
+ rustc_path: &Path,
+ verbose: bool,
+) -> Result<(), Box<dyn Error>> {
+ let mut lines = lint.doc.iter_mut();
+ loop {
+ // Find start of example.
+ let options = loop {
+ match lines.next() {
+ Some(line) if line.starts_with("```rust") => {
+ break line[7..].split(',').collect::<Vec<_>>();
+ }
+ Some(line) if line.contains("{{produces}}") => {
+ return Err("lint marker {{{{produces}}}} found, \
+ but expected to immediately follow a rust code block"
+ .into());
+ }
+ Some(_) => {}
+ None => return Ok(()),
+ }
+ };
+ // Find the end of example.
+ let mut example = Vec::new();
+ loop {
+ match lines.next() {
+ Some(line) if line == "```" => break,
+ Some(line) => example.push(line),
+ None => {
+ return Err(format!(
+ "did not find end of example triple ticks ```, docs were:\n{:?}",
+ lint.doc
+ )
+ .into());
+ }
+ }
+ }
+ // Find the {{produces}} line.
+ loop {
+ match lines.next() {
+ Some(line) if line.is_empty() => {}
+ Some(line) if line == "{{produces}}" => {
+ let output =
+ generate_lint_output(&lint.name, &example, &options, rustc_path, verbose)?;
+ line.replace_range(
+ ..,
+ &format!(
+ "This will produce:\n\
+ \n\
+ ```text\n\
+ {}\
+ ```",
+ output
+ ),
+ );
+ break;
+ }
+ // No {{produces}} after example, find next example.
+ Some(_line) => break,
+ None => return Ok(()),
+ }
+ }
+ }
+}
+
+/// Runs the compiler against the example, and extracts the output.
+fn generate_lint_output(
+ name: &str,
+ example: &[&mut String],
+ options: &[&str],
+ rustc_path: &Path,
+ verbose: bool,
+) -> Result<String, Box<dyn Error>> {
+ if verbose {
+ eprintln!("compiling lint {}", name);
+ }
+ let tempdir = tempfile::TempDir::new()?;
+ let tempfile = tempdir.path().join("lint_example.rs");
+ let mut source = String::new();
+ let needs_main = !example.iter().any(|line| line.contains("fn main"));
+ // Remove `# ` prefix for hidden lines.
+ let unhidden =
+ example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line });
+ let mut lines = unhidden.peekable();
+ while let Some(line) = lines.peek() {
+ if line.starts_with("#!") {
+ source.push_str(line);
+ source.push('\n');
+ lines.next();
+ } else {
+ break;
+ }
+ }
+ if needs_main {
+ source.push_str("fn main() {\n");
+ }
+ for line in lines {
+ source.push_str(line);
+ source.push('\n')
+ }
+ if needs_main {
+ source.push_str("}\n");
+ }
+ fs::write(&tempfile, source)
+ .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?;
+ let mut cmd = Command::new(rustc_path);
+ if options.contains(&"edition2015") {
+ cmd.arg("--edition=2015");
+ } else {
+ cmd.arg("--edition=2018");
+ }
+ cmd.arg("--error-format=json");
+ if options.contains(&"test") {
+ cmd.arg("--test");
+ }
+ cmd.arg("lint_example.rs");
+ cmd.current_dir(tempdir.path());
+ let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
+ let stderr = std::str::from_utf8(&output.stderr).unwrap();
+ let msgs = stderr
+ .lines()
+ .filter(|line| line.starts_with('{'))
+ .map(serde_json::from_str)
+ .collect::<Result<Vec<serde_json::Value>, _>>()?;
+ match msgs
+ .iter()
+ .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
+ {
+ Some(msg) => {
+ let rendered = msg["rendered"].as_str().expect("rendered field should exist");
+ Ok(rendered.to_string())
+ }
+ None => {
+ match msgs.iter().find(
+ |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
+ ) {
+ Some(msg) => {
+ let rendered = msg["rendered"].as_str().expect("rendered field should exist");
+ Ok(rendered.to_string())
+ }
+ None => {
+ let rendered: Vec<&str> =
+ msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
+ let non_json: Vec<&str> =
+ stderr.lines().filter(|line| !line.starts_with('{')).collect();
+ Err(format!(
+ "did not find lint `{}` in output of example, got:\n{}\n{}",
+ name,
+ non_json.join("\n"),
+ rendered.join("\n")
+ )
+ .into())
+ }
+ }
+ }
+ }
+}
+
+static ALLOWED_MD: &str = r#"# Allowed-by-default lints
+
+These lints are all set to the 'allow' level by default. As such, they won't show up
+unless you set them to a higher lint level with a flag or attribute.
+
+"#;
+
+static WARN_MD: &str = r#"# Warn-by-default lints
+
+These lints are all set to the 'warn' level by default.
+
+"#;
+
+static DENY_MD: &str = r#"# Deny-by-default lints
+
+These lints are all set to the 'deny' level by default.
+
+"#;
+
+/// Saves the mdbook lint chapters at the given path.
+fn save_lints_markdown(lints: &[Lint], out_dir: &Path) -> Result<(), Box<dyn Error>> {
+ save_level(lints, Level::Allow, out_dir, ALLOWED_MD)?;
+ save_level(lints, Level::Warn, out_dir, WARN_MD)?;
+ save_level(lints, Level::Deny, out_dir, DENY_MD)?;
+ Ok(())
+}
+
+fn save_level(
+ lints: &[Lint],
+ level: Level,
+ out_dir: &Path,
+ header: &str,
+) -> Result<(), Box<dyn Error>> {
+ let mut result = String::new();
+ result.push_str(header);
+ let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect();
+ these_lints.sort_unstable_by_key(|lint| &lint.name);
+ for lint in &these_lints {
+ write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap();
+ }
+ result.push('\n');
+ for lint in &these_lints {
+ write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap();
+ for line in &lint.doc {
+ result.push_str(line);
+ result.push('\n');
+ }
+ result.push('\n');
+ }
+ let out_path = out_dir.join(level.doc_filename());
+ // Delete the output because rustbuild uses hard links in its copies.
+ let _ = fs::remove_file(&out_path);
+ fs::write(&out_path, result)
+ .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?;
+ Ok(())
+}
--- /dev/null
+use std::error::Error;
+use std::path::PathBuf;
+
+fn main() {
+ if let Err(e) = doit() {
+ println!("error: {}", e);
+ std::process::exit(1);
+ }
+}
+
+fn doit() -> Result<(), Box<dyn Error>> {
+ let mut args = std::env::args().skip(1);
+ let mut src_path = None;
+ let mut out_path = None;
+ let mut rustc_path = None;
+ let mut verbose = false;
+ while let Some(arg) = args.next() {
+ match arg.as_str() {
+ "--src" => {
+ src_path = match args.next() {
+ Some(s) => Some(PathBuf::from(s)),
+ None => return Err("--src requires a value".into()),
+ };
+ }
+ "--out" => {
+ out_path = match args.next() {
+ Some(s) => Some(PathBuf::from(s)),
+ None => return Err("--out requires a value".into()),
+ };
+ }
+ "--rustc" => {
+ rustc_path = match args.next() {
+ Some(s) => Some(PathBuf::from(s)),
+ None => return Err("--rustc requires a value".into()),
+ };
+ }
+ "-v" | "--verbose" => verbose = true,
+ s => return Err(format!("unexpected argument `{}`", s).into()),
+ }
+ }
+ if src_path.is_none() {
+ return Err("--src must be specified to the directory with the compiler source".into());
+ }
+ if out_path.is_none() {
+ return Err("--out must be specified to the directory with the lint listing docs".into());
+ }
+ if rustc_path.is_none() {
+ return Err("--rustc must be specified to the path of rustc".into());
+ }
+ lint_docs::extract_lint_docs(
+ &src_path.unwrap(),
+ &out_path.unwrap(),
+ &rustc_path.unwrap(),
+ verbose,
+ )
+}
-Subproject commit 0275b08d1521606fa733f76fe5d5707717456fb4
+Subproject commit 0d03fe6ef57d3956e92382e0e1f1a916015191cb