strategy:
matrix:
include:
- - name: dist-x86_64-apple
- env:
- SCRIPT: "./x.py dist --exclude src/doc --exclude extended && ./x.py dist --target=x86_64-apple-darwin src/doc && ./x.py dist extended"
- RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --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-linux
+ os: ubuntu-latest-xl
+ env: {}
timeout-minutes: 600
runs-on: "${{ matrix.os }}"
steps:
Guillaume Gomez <guillaume1.gomez@gmail.com>
Guillaume Gomez <guillaume1.gomez@gmail.com> ggomez <ggomez@ggo.ifr.lan>
Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <ggomez@ggo.ifr.lan>
+Guillaume Gomez <guillaume1.gomez@gmail.com> Guillaume Gomez <guillaume.gomez@huawei.com>
Hanna Kruppe <hanna.kruppe@gmail.com> <robin.kruppe@gmail.com>
Heather <heather@cynede.net> <Cynede@Gentoo.org>
Heather <heather@cynede.net> <Heather@cynede.net>
[[package]]
name = "cargo"
-version = "0.58.0"
+version = "0.59.0"
dependencies = [
"anyhow",
"atty",
name = "clippy"
version = "0.1.58"
dependencies = [
- "cargo_metadata 0.12.0",
+ "cargo_metadata 0.14.0",
"clippy_lints",
"clippy_utils",
"compiletest_rs",
"regex",
"rustc-workspace-hack",
"rustc_tools_util 0.2.0",
- "semver 0.11.0",
+ "semver 1.0.3",
"serde",
"syn",
"tempfile",
name = "clippy_lints"
version = "0.1.58"
dependencies = [
- "cargo_metadata 0.12.0",
+ "cargo_metadata 0.14.0",
"clippy_utils",
"if_chain",
"itertools 0.10.1",
"quine-mc_cluskey",
"regex-syntax",
"rustc-semver",
- "semver 0.11.0",
+ "semver 1.0.3",
"serde",
"serde_json",
"toml",
[[package]]
name = "compiletest_rs"
-version = "0.7.0"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64698e5e2435db061a85e6320af12c30c5fd88eb84b35d2c1e03ce4f143255ca"
+checksum = "29843cb8d351febf86557681d049d1e1652b81a086a190fa1173c07fd17fbf83"
dependencies = [
"diff",
"filetime",
[[package]]
name = "curl"
-version = "0.4.39"
+version = "0.4.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aaa3b8db7f3341ddef15786d250106334d4a6c4b0ae4a46cd77082777d9849b9"
+checksum = "877cc2f9b8367e32b6dabb9d581557e651cb3aa693a37f8679091bbf42687d5d"
dependencies = [
"curl-sys",
"libc",
[[package]]
name = "curl-sys"
-version = "0.4.49+curl-7.79.1"
+version = "0.4.50+curl-7.79.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0f44960aea24a786a46907b8824ebc0e66ca06bf4e4978408c7499620343483"
+checksum = "4856b76919dd599f31236bb18db5f5bd36e2ce131e64f857ca5c259665b76171"
dependencies = [
"cc",
"libc",
[[package]]
name = "libc"
-version = "0.2.103"
+version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
+checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673"
dependencies = [
"rustc-std-workspace-core",
]
[[package]]
name = "odht"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2504d29fda40b3f2f9ef525392435ab660e407c188196cb664b116ebcca0142"
+checksum = "5a518809ac14b25b569624d0268eba1e88498f71615893dca57982bed7621abb"
dependencies = [
"cfg-if 1.0.0",
]
"rustc_span",
"tracing",
"unicode-normalization",
+ "unicode-width",
]
[[package]]
"itertools 0.9.0",
"minifier",
"pulldown-cmark 0.8.0",
+ "rayon",
"regex",
- "rustc-rayon",
"rustdoc-json-types",
"serde",
"serde_json",
+Version 1.56.1 (2021-11-01)
+===========================
+
+- New lints to detect the presence of bidirectional-override Unicode
+ codepoints in the compiled source code ([CVE-2021-42574])
+
+[CVE-2021-42574]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-42574
+
Version 1.56.0 (2021-10-21)
========================
The `rustc_ast` crate contains those things concerned purely with syntax
-– that is, the AST ("abstract syntax tree"), parser, pretty-printer,
-lexer, macro expander, and utilities for traversing ASTs.
+– that is, the AST ("abstract syntax tree"), along with some definitions for tokens and token streams, data structures/traits for mutating ASTs, and shared definitions for other AST-related parts of the compiler (like the lexer and macro-expansion).
For more information about how these things work in rustc, see the
rustc dev guide:
}
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct TraitKind(
- pub IsAuto,
- pub Unsafe,
- pub Generics,
- pub GenericBounds,
- pub Vec<P<AssocItem>>,
-);
+pub struct Trait {
+ pub unsafety: Unsafe,
+ pub is_auto: IsAuto,
+ pub generics: Generics,
+ pub bounds: GenericBounds,
+ pub items: Vec<P<AssocItem>>,
+}
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct TyAliasKind(pub Defaultness, pub Generics, pub GenericBounds, pub Option<P<Ty>>);
+pub struct TyAlias {
+ pub defaultness: Defaultness,
+ pub generics: Generics,
+ pub bounds: GenericBounds,
+ pub ty: Option<P<Ty>>,
+}
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct ImplKind {
- pub unsafety: Unsafe,
- pub polarity: ImplPolarity,
+pub struct Impl {
pub defaultness: Defaultness,
- pub constness: Const,
+ pub unsafety: Unsafe,
pub generics: Generics,
-
+ pub constness: Const,
+ pub polarity: ImplPolarity,
/// The trait being implemented, if any.
pub of_trait: Option<TraitRef>,
-
pub self_ty: P<Ty>,
pub items: Vec<P<AssocItem>>,
}
#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct FnKind(pub Defaultness, pub FnSig, pub Generics, pub Option<P<Block>>);
+pub struct Fn {
+ pub defaultness: Defaultness,
+ pub generics: Generics,
+ pub sig: FnSig,
+ pub body: Option<P<Block>>,
+}
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum ItemKind {
/// A function declaration (`fn`).
///
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
- Fn(Box<FnKind>),
+ Fn(Box<Fn>),
/// A module declaration (`mod`).
///
/// E.g., `mod foo;` or `mod foo { .. }`.
/// A type alias (`type`).
///
/// E.g., `type Foo = Bar<u8>;`.
- TyAlias(Box<TyAliasKind>),
+ TyAlias(Box<TyAlias>),
/// An enum definition (`enum`).
///
/// E.g., `enum Foo<A, B> { C<A>, D<B> }`.
/// A trait declaration (`trait`).
///
/// E.g., `trait Foo { .. }`, `trait Foo<T> { .. }` or `auto trait Foo {}`.
- Trait(Box<TraitKind>),
+ Trait(Box<Trait>),
/// Trait alias
///
/// E.g., `trait Foo = Bar + Quux;`.
/// An implementation.
///
/// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`.
- Impl(Box<ImplKind>),
+ Impl(Box<Impl>),
/// A macro invocation.
///
/// E.g., `foo!(..)`.
pub fn generics(&self) -> Option<&Generics> {
match self {
- Self::Fn(box FnKind(_, _, generics, _))
- | Self::TyAlias(box TyAliasKind(_, generics, ..))
+ Self::Fn(box Fn { generics, .. })
+ | Self::TyAlias(box TyAlias { generics, .. })
| Self::Enum(_, generics)
| Self::Struct(_, generics)
| Self::Union(_, generics)
- | Self::Trait(box TraitKind(_, _, generics, ..))
+ | Self::Trait(box Trait { generics, .. })
| Self::TraitAlias(generics, _)
- | Self::Impl(box ImplKind { generics, .. }) => Some(generics),
+ | Self::Impl(box Impl { generics, .. }) => Some(generics),
_ => None,
}
}
/// If `def` is parsed, then the constant is provided, and otherwise required.
Const(Defaultness, P<Ty>, Option<P<Expr>>),
/// An associated function.
- Fn(Box<FnKind>),
+ Fn(Box<Fn>),
/// An associated type.
- TyAlias(Box<TyAliasKind>),
+ TyAlias(Box<TyAlias>),
/// A macro expanding to associated items.
MacCall(MacCall),
}
impl AssocItemKind {
pub fn defaultness(&self) -> Defaultness {
match *self {
- Self::Const(def, ..)
- | Self::Fn(box FnKind(def, ..))
- | Self::TyAlias(box TyAliasKind(def, ..)) => def,
+ Self::Const(defaultness, ..)
+ | Self::Fn(box Fn { defaultness, .. })
+ | Self::TyAlias(box TyAlias { defaultness, .. }) => defaultness,
Self::MacCall(..) => Defaultness::Final,
}
}
/// A foreign static item (`static FOO: u8`).
Static(P<Ty>, Mutability, Option<P<Expr>>),
/// An foreign function.
- Fn(Box<FnKind>),
+ Fn(Box<Fn>),
/// An foreign type.
- TyAlias(Box<TyAliasKind>),
+ TyAlias(Box<TyAlias>),
/// A macro expanding to foreign items.
MacCall(MacCall),
}
-//! The Rust parser and macro expander.
+//! The Rust Abstract Syntax Tree (AST).
//!
//! # Note
//!
#![feature(nll)]
#![feature(min_specialization)]
#![recursion_limit = "256"]
+#![feature(slice_internals)]
#[macro_use]
extern crate rustc_macros;
pub mod comments;
pub mod literal;
pub mod parser;
+ pub mod unicode;
}
pub mod ast;
vis.visit_mt(mt);
}
TyKind::BareFn(bft) => {
- let BareFnTy { unsafety: _, ext: _, generic_params, decl } = bft.deref_mut();
+ let BareFnTy { unsafety, ext: _, generic_params, decl } = bft.deref_mut();
+ visit_unsafety(unsafety, vis);
generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
vis.visit_fn_decl(decl);
}
}
pub fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
- let ForeignMod { unsafety: _, abi: _, items } = foreign_mod;
+ let ForeignMod { unsafety, abi: _, items } = foreign_mod;
+ visit_unsafety(unsafety, vis);
items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
}
}
}
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_defaultness<T: MutVisitor>(defaultness: &mut Defaultness, vis: &mut T) {
+ match defaultness {
+ Defaultness::Default(span) => vis.visit_span(span),
+ Defaultness::Final => {}
+ }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_unsafety<T: MutVisitor>(unsafety: &mut Unsafe, vis: &mut T) {
+ match unsafety {
+ Unsafe::Yes(span) => vis.visit_span(span),
+ Unsafe::No => {}
+ }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_polarity<T: MutVisitor>(polarity: &mut ImplPolarity, vis: &mut T) {
+ match polarity {
+ ImplPolarity::Positive => {}
+ ImplPolarity::Negative(span) => vis.visit_span(span),
+ }
+}
+
+// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
+pub fn visit_constness<T: MutVisitor>(constness: &mut Const, vis: &mut T) {
+ match constness {
+ Const::Yes(span) => vis.visit_span(span),
+ Const::No => {}
+ }
+}
+
pub fn noop_visit_asyncness<T: MutVisitor>(asyncness: &mut Async, vis: &mut T) {
match asyncness {
Async::Yes { span: _, closure_id, return_impl_trait_id } => {
match kind {
ItemKind::ExternCrate(_orig_name) => {}
ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
- ItemKind::Static(ty, _, expr) | ItemKind::Const(_, ty, expr) => {
+ ItemKind::Static(ty, _, expr) => {
vis.visit_ty(ty);
visit_opt(expr, |expr| vis.visit_expr(expr));
}
- ItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ ItemKind::Const(defaultness, ty, expr) => {
+ visit_defaultness(defaultness, vis);
+ vis.visit_ty(ty);
+ visit_opt(expr, |expr| vis.visit_expr(expr));
+ }
+ ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+ visit_defaultness(defaultness, vis);
visit_fn_sig(sig, vis);
vis.visit_generics(generics);
visit_opt(body, |body| vis.visit_block(body));
}
- ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
- ModKind::Loaded(items, _inline, inner_span) => {
- vis.visit_span(inner_span);
- items.flat_map_in_place(|item| vis.flat_map_item(item));
+ ItemKind::Mod(unsafety, mod_kind) => {
+ visit_unsafety(unsafety, vis);
+ match mod_kind {
+ ModKind::Loaded(items, _inline, inner_span) => {
+ vis.visit_span(inner_span);
+ items.flat_map_in_place(|item| vis.flat_map_item(item));
+ }
+ ModKind::Unloaded => {}
}
- ModKind::Unloaded => {}
- },
+ }
ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
ItemKind::GlobalAsm(asm) => noop_visit_inline_asm(asm, vis),
- ItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ ItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ visit_defaultness(defaultness, vis);
vis.visit_generics(generics);
visit_bounds(bounds, vis);
visit_opt(ty, |ty| vis.visit_ty(ty));
vis.visit_variant_data(variant_data);
vis.visit_generics(generics);
}
- ItemKind::Impl(box ImplKind {
- unsafety: _,
- polarity: _,
- defaultness: _,
- constness: _,
+ ItemKind::Impl(box Impl {
+ defaultness,
+ unsafety,
generics,
+ constness,
+ polarity,
of_trait,
self_ty,
items,
}) => {
+ visit_defaultness(defaultness, vis);
+ visit_unsafety(unsafety, vis);
vis.visit_generics(generics);
+ visit_constness(constness, vis);
+ visit_polarity(polarity, vis);
visit_opt(of_trait, |trait_ref| vis.visit_trait_ref(trait_ref));
vis.visit_ty(self_ty);
items.flat_map_in_place(|item| vis.flat_map_impl_item(item));
}
- ItemKind::Trait(box TraitKind(.., generics, bounds, items)) => {
+ ItemKind::Trait(box Trait { unsafety, is_auto: _, generics, bounds, items }) => {
+ visit_unsafety(unsafety, vis);
vis.visit_generics(generics);
visit_bounds(bounds, vis);
items.flat_map_in_place(|item| vis.flat_map_trait_item(item));
visitor.visit_vis(vis);
visit_attrs(attrs, visitor);
match kind {
- AssocItemKind::Const(_, ty, expr) => {
+ AssocItemKind::Const(defaultness, ty, expr) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_ty(ty);
visit_opt(expr, |expr| visitor.visit_expr(expr));
}
- AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ AssocItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty));
}
pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
- let FnHeader { unsafety: _, asyncness, constness: _, ext: _ } = header;
+ let FnHeader { unsafety, asyncness, constness, ext: _ } = header;
+ visit_constness(constness, vis);
vis.visit_asyncness(asyncness);
+ visit_unsafety(unsafety, vis);
}
// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible,
visitor.visit_ty(ty);
visit_opt(expr, |expr| visitor.visit_expr(expr));
}
- ForeignItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_fn_sig(sig, visitor);
visit_opt(body, |body| visitor.visit_block(body));
}
- ForeignItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty }) => {
+ visit_defaultness(defaultness, visitor);
visitor.visit_generics(generics);
visit_bounds(bounds, visitor);
visit_opt(ty, |ty| visitor.visit_ty(ty));
for attr in &data.attrs {
match attr.style {
crate::AttrStyle::Outer => {
- assert!(
- inner_attrs.len() == 0,
- "Found outer attribute {:?} after inner attrs {:?}",
- attr,
- inner_attrs
- );
outer_attrs.push(attr);
}
crate::AttrStyle::Inner => {
i += 1;
}
// like the first, a last line of all stars should be omitted
- if j > i && lines[j - 1].chars().skip(1).all(|c| c == '*') {
+ if j > i && !lines[j - 1].is_empty() && lines[j - 1].chars().all(|c| c == '*') {
j -= 1;
}
/// parentheses while having a high degree of confidence on the correctness of the suggestion.
pub fn can_continue_expr_unambiguously(&self) -> bool {
use AssocOp::*;
- match self {
+ matches!(
+ self,
BitXor | // `{ 42 } ^ 3`
Assign | // `{ 42 } = { 42 }`
Divide | // `{ 42 } / 42`
As | // `{ 42 } as usize`
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
// NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
- Colon => true, // `{ 42 }: usize`
- _ => false,
- }
+ Colon, // `{ 42 }: usize`
+ )
}
}
--- /dev/null
+pub const TEXT_FLOW_CONTROL_CHARS: &[char] = &[
+ '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}',
+ '\u{2069}',
+];
+
+#[inline]
+pub fn contains_text_flow_control_chars(s: &str) -> bool {
+ // Char - UTF-8
+ // U+202A - E2 80 AA
+ // U+202B - E2 80 AB
+ // U+202C - E2 80 AC
+ // U+202D - E2 80 AD
+ // U+202E - E2 80 AE
+ // U+2066 - E2 81 A6
+ // U+2067 - E2 81 A7
+ // U+2068 - E2 81 A8
+ // U+2069 - E2 81 A9
+ let mut bytes = s.as_bytes();
+ loop {
+ match core::slice::memchr::memchr(0xE2, &bytes) {
+ Some(idx) => {
+ // bytes are valid UTF-8 -> E2 must be followed by two bytes
+ let ch = &bytes[idx..idx + 3];
+ match ch {
+ [_, 0x80, 0xAA..=0xAE] | [_, 0x81, 0xA6..=0xA9] => break true,
+ _ => {}
+ }
+ bytes = &bytes[idx + 3..];
+ }
+ None => {
+ break false;
+ }
+ }
+ }
+}
visitor.visit_ty(typ);
walk_list!(visitor, visit_expr, expr);
}
- ItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body)) => {
+ ItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Free, item.ident, sig, &item.vis, body.as_deref());
visitor.visit_fn(kind, item.span, item.id)
walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
ItemKind::GlobalAsm(ref asm) => walk_inline_asm(visitor, asm),
- ItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty)) => {
+ ItemKind::TyAlias(box TyAlias { defaultness: _, ref generics, ref bounds, ref ty }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
visitor.visit_generics(generics);
visitor.visit_enum_def(enum_definition, generics, item.id, item.span)
}
- ItemKind::Impl(box ImplKind {
- unsafety: _,
- polarity: _,
+ ItemKind::Impl(box Impl {
defaultness: _,
- constness: _,
+ unsafety: _,
ref generics,
+ constness: _,
+ polarity: _,
ref of_trait,
ref self_ty,
ref items,
visitor.visit_generics(generics);
visitor.visit_variant_data(struct_definition);
}
- ItemKind::Trait(box TraitKind(.., ref generics, ref bounds, ref items)) => {
+ ItemKind::Trait(box Trait {
+ unsafety: _,
+ is_auto: _,
+ ref generics,
+ ref bounds,
+ ref items,
+ }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
- ForeignItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ ForeignItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- ForeignItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ ForeignItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
visitor.visit_ty(ty);
walk_list!(visitor, visit_expr, expr);
}
- AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ AssocItemKind::Fn(box Fn { defaultness: _, ref generics, ref sig, ref body }) => {
visitor.visit_generics(generics);
let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, body.as_deref());
visitor.visit_fn(kind, span, id);
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, bounds, ty)) => {
+ AssocItemKind::TyAlias(box TyAlias { defaultness: _, generics, bounds, ty }) => {
visitor.visit_generics(generics);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_ty, ty);
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_span::{Span, Symbol};
+use rustc_session::parse::feature_err;
+use rustc_span::{sym, Span, Symbol};
use rustc_target::asm;
use std::collections::hash_map::Entry;
use std::fmt::Write;
impl<'a, 'hir> LoweringContext<'a, 'hir> {
crate fn lower_inline_asm(&mut self, sp: Span, asm: &InlineAsm) -> &'hir hir::InlineAsm<'hir> {
- // Rustdoc needs to support asm! from foriegn architectures: don't try
- // lowering the register contraints in this case.
+ // Rustdoc needs to support asm! from foreign architectures: don't try
+ // lowering the register constraints in this case.
let asm_arch = if self.sess.opts.actually_rustdoc { None } else { self.sess.asm_arch };
if asm_arch.is_none() && !self.sess.opts.actually_rustdoc {
struct_span_err!(self.sess, sp, E0472, "inline assembly is unsupported on this target")
.emit();
}
+ if let Some(asm_arch) = asm_arch {
+ // Inline assembly is currently only stable for these architectures.
+ let is_stable = matches!(
+ asm_arch,
+ asm::InlineAsmArch::X86
+ | asm::InlineAsmArch::X86_64
+ | asm::InlineAsmArch::Arm
+ | asm::InlineAsmArch::AArch64
+ | asm::InlineAsmArch::RiscV32
+ | asm::InlineAsmArch::RiscV64
+ );
+ if !is_stable && !self.sess.features_untracked().asm_experimental_arch {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::asm_experimental_arch,
+ sp,
+ "inline assembly is not stable yet on this architecture",
+ )
+ .emit();
+ }
+ }
if asm.options.contains(InlineAsmOptions::ATT_SYNTAX)
&& !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
&& !self.sess.opts.actually_rustdoc
out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)),
}
}
- InlineAsmOperand::Const { ref anon_const } => hir::InlineAsmOperand::Const {
- anon_const: self.lower_anon_const(anon_const),
- },
+ InlineAsmOperand::Const { ref anon_const } => {
+ if !self.sess.features_untracked().asm_const {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::asm_const,
+ *op_sp,
+ "const operands for inline assembly are unstable",
+ )
+ .emit();
+ }
+ hir::InlineAsmOperand::Const {
+ anon_const: self.lower_anon_const(anon_const),
+ }
+ }
InlineAsmOperand::Sym { ref expr } => {
+ if !self.sess.features_untracked().asm_sym {
+ feature_err(
+ &self.sess.parse_sess,
+ sym::asm_sym,
+ *op_sp,
+ "sym operands for inline assembly are unstable",
+ )
+ .emit();
+ }
hir::InlineAsmOperand::Sym { expr: self.lower_expr_mut(expr) }
}
};
// means that we disallow passing a value in/out of the asm and
// require that the operand name an explicit register, not a
// register class.
- if reg_class.is_clobber_only(asm_arch.unwrap())
- && !(op.is_clobber() && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
- {
+ if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
let msg = format!(
"register class `{}` can only be used as a clobber, \
not as an input or output",
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sorted_map::SortedMap;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::definitions;
use rustc_span::source_map::SourceMap;
use rustc_span::{Span, DUMMY_SP};
-use std::iter::repeat;
use tracing::debug;
/// A visitor that walks over the HIR and collects `Node`s into a HIR map.
pub(super) struct NodeCollector<'a, 'hir> {
/// Source map
source_map: &'a SourceMap,
- bodies: &'a IndexVec<ItemLocalId, Option<&'hir Body<'hir>>>,
+ bodies: &'a SortedMap<ItemLocalId, &'hir Body<'hir>>,
/// Outputs
nodes: IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>,
definitions: &'a definitions::Definitions,
}
-fn insert_vec_map<K: Idx, V: Clone>(map: &mut IndexVec<K, Option<V>>, k: K, v: V) {
- let i = k.index();
- let len = map.len();
- if i >= len {
- map.extend(repeat(None).take(i - len + 1));
- }
- debug_assert!(map[k].is_none());
- map[k] = Some(v);
-}
-
pub(super) fn index_hir<'hir>(
sess: &Session,
definitions: &definitions::Definitions,
item: hir::OwnerNode<'hir>,
- bodies: &IndexVec<ItemLocalId, Option<&'hir Body<'hir>>>,
+ bodies: &SortedMap<ItemLocalId, &'hir Body<'hir>>,
) -> (IndexVec<ItemLocalId, Option<ParentedNode<'hir>>>, FxHashMap<LocalDefId, ItemLocalId>) {
let mut nodes = IndexVec::new();
// This node's parent should never be accessed: the owner's parent is computed by the
}
}
- insert_vec_map(
- &mut self.nodes,
- hir_id.local_id,
- ParentedNode { parent: self.parent_node, node: node },
- );
+ self.nodes.insert(hir_id.local_id, ParentedNode { parent: self.parent_node, node: node });
}
fn with_parent<F: FnOnce(&mut Self)>(&mut self, parent_node_id: HirId, f: F) {
fn visit_nested_body(&mut self, id: BodyId) {
debug_assert_eq!(id.hir_id.owner, self.owner);
- let body = self.bodies[id.hir_id.local_id].unwrap();
+ let body = self.bodies[&id.hir_id.local_id];
self.visit_body(body);
}
self.lctx.with_parent_item_lifetime_defs(hir_id, |this| {
let this = &mut ItemLowerer { lctx: this };
match item.kind {
- ItemKind::Impl(box ImplKind { ref of_trait, .. }) => {
+ ItemKind::Impl(box Impl { ref of_trait, .. }) => {
this.with_trait_impl_ref(of_trait, |this| visit::walk_item(this, item));
}
_ => visit::walk_item(this, item),
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
hir::ItemKind::Const(ty, body_id)
}
- ItemKind::Fn(box FnKind(
- _,
- FnSig { ref decl, header, span: fn_sig_span },
+ ItemKind::Fn(box Fn {
+ sig: FnSig { ref decl, header, span: fn_sig_span },
ref generics,
ref body,
- )) => {
+ ..
+ }) => {
let fn_def_id = self.resolver.local_def_id(id);
self.with_new_scopes(|this| {
this.current_item = Some(ident.span);
ItemKind::GlobalAsm(ref asm) => {
hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm))
}
- ItemKind::TyAlias(box TyAliasKind(_, ref gen, _, Some(ref ty))) => {
+ ItemKind::TyAlias(box TyAlias { ref generics, ty: Some(ref ty), .. }) => {
// We lower
//
// type Foo = impl Trait
capturable_lifetimes: &mut FxHashSet::default(),
},
);
- let generics = self.lower_generics(gen, ImplTraitContext::disallowed());
+ let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
hir::ItemKind::TyAlias(ty, generics)
}
- ItemKind::TyAlias(box TyAliasKind(_, ref generics, _, None)) => {
+ ItemKind::TyAlias(box TyAlias { ref generics, ty: None, .. }) => {
let ty = self.arena.alloc(self.ty(span, hir::TyKind::Err));
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
hir::ItemKind::TyAlias(ty, generics)
self.lower_generics(generics, ImplTraitContext::disallowed()),
)
}
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
unsafety,
polarity,
defaultness,
items: new_impl_items,
})
}
- ItemKind::Trait(box TraitKind(
+ ItemKind::Trait(box Trait {
is_auto,
unsafety,
ref generics,
ref bounds,
ref items,
- )) => {
+ }) => {
let bounds = self.lower_param_bounds(bounds, ImplTraitContext::disallowed());
let items = self
.arena
def_id,
ident: self.lower_ident(i.ident),
kind: match i.kind {
- ForeignItemKind::Fn(box FnKind(_, ref sig, ref generics, _)) => {
+ ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
let fdec = &sig.decl;
let (generics, (fn_dec, fn_args)) = self.add_in_band_defs(
generics,
let body = default.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body))
}
- AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, None)) => {
+ AssocItemKind::Fn(box Fn { ref sig, ref generics, body: None, .. }) => {
let names = self.lower_fn_params_to_names(&sig.decl);
let (generics, sig) =
self.lower_method_sig(generics, sig, trait_item_def_id, false, None);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)))
}
- AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, Some(ref body))) => {
+ AssocItemKind::Fn(box Fn { ref sig, ref generics, body: Some(ref body), .. }) => {
let asyncness = sig.header.asyncness;
let body_id =
self.lower_maybe_async_body(i.span, &sig.decl, asyncness, Some(&body));
);
(generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)))
}
- AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref default)) => {
- let ty = default.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
+ AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. }) => {
+ let ty = ty.as_ref().map(|x| self.lower_ty(x, ImplTraitContext::disallowed()));
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
let kind = hir::TraitItemKind::Type(
self.lower_param_bounds(bounds, ImplTraitContext::disallowed()),
fn lower_trait_item_ref(&mut self, i: &AssocItem) -> hir::TraitItemRef {
let (kind, has_default) = match &i.kind {
AssocItemKind::Const(_, _, default) => (hir::AssocItemKind::Const, default.is_some()),
- AssocItemKind::TyAlias(box TyAliasKind(_, _, _, default)) => {
- (hir::AssocItemKind::Type, default.is_some())
+ AssocItemKind::TyAlias(box TyAlias { ty, .. }) => {
+ (hir::AssocItemKind::Type, ty.is_some())
}
- AssocItemKind::Fn(box FnKind(_, sig, _, default)) => {
- (hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, default.is_some())
+ AssocItemKind::Fn(box Fn { sig, body, .. }) => {
+ (hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }, body.is_some())
}
AssocItemKind::MacCall(..) => unimplemented!(),
};
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
)
}
- AssocItemKind::Fn(box FnKind(_, sig, generics, body)) => {
+ AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
self.current_item = Some(i.span);
let asyncness = sig.header.asyncness;
let body_id =
(generics, hir::ImplItemKind::Fn(sig, body_id))
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, _, ty)) => {
+ AssocItemKind::TyAlias(box TyAlias { generics, ty, .. }) => {
let generics = self.lower_generics(generics, ImplTraitContext::disallowed());
let kind = match ty {
None => {
kind: match &i.kind {
AssocItemKind::Const(..) => hir::AssocItemKind::Const,
AssocItemKind::TyAlias(..) => hir::AssocItemKind::Type,
- AssocItemKind::Fn(box FnKind(_, sig, ..)) => {
+ AssocItemKind::Fn(box Fn { sig, .. }) => {
hir::AssocItemKind::Fn { has_self: sig.decl.has_self() }
}
AssocItemKind::MacCall(..) => unimplemented!(),
let body = hir::Body { generator_kind: self.generator_kind, params, value };
let id = body.id();
debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
- self.bodies.ensure_contains_elem(id.hir_id.local_id, || None);
- self.bodies[id.hir_id.local_id] = Some(self.arena.alloc(body));
+ self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
id
}
#![feature(iter_zip)]
#![feature(never_type)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream, TokenTree};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{struct_span_err, Applicability};
use rustc_span::{Span, DUMMY_SP};
use smallvec::SmallVec;
-use std::collections::BTreeMap;
use tracing::{debug, trace};
macro_rules! arena_vec {
/// The items being lowered are collected here.
owners: IndexVec<LocalDefId, Option<hir::OwnerInfo<'hir>>>,
/// Bodies inside the owner being lowered.
- bodies: IndexVec<hir::ItemLocalId, Option<&'hir hir::Body<'hir>>>,
+ bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>,
/// Attributes inside the owner being lowered.
- attrs: BTreeMap<hir::ItemLocalId, &'hir [Attribute]>,
+ attrs: SortedMap<hir::ItemLocalId, &'hir [Attribute]>,
generator_kind: Option<hir::GeneratorKind>,
nt_to_tokenstream,
arena,
owners,
- bodies: IndexVec::new(),
- attrs: BTreeMap::default(),
+ bodies: Vec::new(),
+ attrs: SortedMap::new(),
catch_scope: None,
loop_scope: None,
is_in_loop_condition: false,
fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> hir::OwnerInfo<'hir> {
let attrs = std::mem::take(&mut self.attrs);
- let bodies = std::mem::take(&mut self.bodies);
+ let mut bodies = std::mem::take(&mut self.bodies);
let local_node_ids = std::mem::take(&mut self.local_node_ids);
let trait_map = local_node_ids
.into_iter()
.collect();
#[cfg(debug_assertions)]
- for (&id, attrs) in attrs.iter() {
+ for (id, attrs) in attrs.iter() {
// Verify that we do not store empty slices in the map.
if attrs.is_empty() {
panic!("Stored empty attributes for {:?}", id);
}
}
+ bodies.sort_by_key(|(k, _)| *k);
+ let bodies = SortedMap::from_presorted_elements(bodies);
let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
let (nodes, parenting) =
index::index_hir(self.sess, self.resolver.definitions(), node, &bodies);
fn hash_owner(
&mut self,
node: hir::OwnerNode<'hir>,
- bodies: &IndexVec<hir::ItemLocalId, Option<&'hir hir::Body<'hir>>>,
+ bodies: &SortedMap<hir::ItemLocalId, &'hir hir::Body<'hir>>,
) -> (Fingerprint, Fingerprint) {
let mut hcx = self.resolver.create_stable_hashing_context();
let mut stable_hasher = StableHasher::new();
}
match item.kind {
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
unsafety,
polarity,
defaultness: _,
});
return; // Avoid visiting again.
}
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
unsafety,
polarity,
defaultness,
.emit();
}
}
- ItemKind::Fn(box FnKind(def, ref sig, ref generics, ref body)) => {
- self.check_defaultness(item.span, def);
+ ItemKind::Fn(box Fn { defaultness, ref sig, ref generics, ref body }) => {
+ self.check_defaultness(item.span, defaultness);
if body.is_none() {
let msg = "free function without a body";
}
}
}
- ItemKind::Trait(box TraitKind(
- is_auto,
- _,
- ref generics,
- ref bounds,
- ref trait_items,
- )) => {
+ ItemKind::Trait(box Trait { is_auto, ref generics, ref bounds, ref items, .. }) => {
if is_auto == IsAuto::Yes {
// Auto traits cannot have generics, super traits nor contain items.
self.deny_generic_params(generics, item.ident.span);
self.deny_super_traits(bounds, item.ident.span);
self.deny_where_clause(&generics.where_clause, item.ident.span);
- self.deny_items(trait_items, item.ident.span);
+ self.deny_items(items, item.ident.span);
}
self.no_questions_in_bounds(bounds, "supertraits", true);
self.visit_ident(item.ident);
self.visit_generics(generics);
self.with_banned_tilde_const(|this| walk_list!(this, visit_param_bound, bounds));
- walk_list!(self, visit_assoc_item, trait_items, AssocCtxt::Trait);
+ walk_list!(self, visit_assoc_item, items, AssocCtxt::Trait);
walk_list!(self, visit_attribute, &item.attrs);
return;
}
let msg = "free static item without body";
self.error_item_without_body(item.span, "static", msg, " = <expr>;");
}
- ItemKind::TyAlias(box TyAliasKind(def, _, ref bounds, ref body)) => {
- self.check_defaultness(item.span, def);
- if body.is_none() {
+ ItemKind::TyAlias(box TyAlias { defaultness, ref bounds, ref ty, .. }) => {
+ self.check_defaultness(item.span, defaultness);
+ if ty.is_none() {
let msg = "free type alias without body";
self.error_item_without_body(item.span, "type", msg, " = <type>;");
}
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
match &fi.kind {
- ForeignItemKind::Fn(box FnKind(def, sig, _, body)) => {
- self.check_defaultness(fi.span, *def);
+ ForeignItemKind::Fn(box Fn { defaultness, sig, body, .. }) => {
+ self.check_defaultness(fi.span, *defaultness);
self.check_foreign_fn_bodyless(fi.ident, body.as_deref());
self.check_foreign_fn_headerless(fi.ident, fi.span, sig.header);
self.check_foreign_item_ascii_only(fi.ident);
}
- ForeignItemKind::TyAlias(box TyAliasKind(def, generics, bounds, body)) => {
- self.check_defaultness(fi.span, *def);
- self.check_foreign_kind_bodyless(fi.ident, "type", body.as_ref().map(|b| b.span));
+ ForeignItemKind::TyAlias(box TyAlias { defaultness, generics, bounds, ty, .. }) => {
+ self.check_defaultness(fi.span, *defaultness);
+ self.check_foreign_kind_bodyless(fi.ident, "type", ty.as_ref().map(|b| b.span));
self.check_type_no_bounds(bounds, "`extern` blocks");
self.check_foreign_ty_genericless(generics);
self.check_foreign_item_ascii_only(fi.ident);
AssocItemKind::Const(_, _, body) => {
self.check_impl_item_provided(item.span, body, "constant", " = <expr>;");
}
- AssocItemKind::Fn(box FnKind(_, _, _, body)) => {
+ AssocItemKind::Fn(box Fn { body, .. }) => {
self.check_impl_item_provided(item.span, body, "function", " { <body> }");
}
- AssocItemKind::TyAlias(box TyAliasKind(_, _, bounds, body)) => {
- self.check_impl_item_provided(item.span, body, "type", " = <type>;");
+ AssocItemKind::TyAlias(box TyAlias { bounds, ty, .. }) => {
+ self.check_impl_item_provided(item.span, ty, "type", " = <type>;");
self.check_type_no_bounds(bounds, "`impl`s");
}
_ => {}
if ctxt == AssocCtxt::Trait || self.in_trait_impl {
self.invalid_visibility(&item.vis, None);
- if let AssocItemKind::Fn(box FnKind(_, sig, _, _)) = &item.kind {
+ if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
self.check_trait_fn_not_const(sig.header.constness);
self.check_trait_fn_not_async(item.span, sig.header.asyncness);
}
}
match item.kind {
- AssocItemKind::TyAlias(box TyAliasKind(_, ref generics, ref bounds, ref ty))
+ AssocItemKind::TyAlias(box TyAlias { ref generics, ref bounds, ref ty, .. })
if ctxt == AssocCtxt::Trait =>
{
self.visit_vis(&item.vis);
});
walk_list!(self, visit_ty, ty);
}
- AssocItemKind::Fn(box FnKind(_, ref sig, ref generics, ref body))
+ AssocItemKind::Fn(box Fn { ref sig, ref generics, ref body, .. })
if self.in_const_trait_impl
|| ctxt == AssocCtxt::Trait
|| matches!(sig.header.constness, Const::Yes(_)) =>
}
}
- ast::ItemKind::Impl(box ast::ImplKind {
- polarity, defaultness, ref of_trait, ..
- }) => {
+ ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, ref of_trait, .. }) => {
if let ast::ImplPolarity::Negative(span) = polarity {
gate_feature_post!(
&self,
}
}
- ast::ItemKind::Trait(box ast::TraitKind(ast::IsAuto::Yes, ..)) => {
+ ast::ItemKind::Trait(box ast::Trait { is_auto: ast::IsAuto::Yes, .. }) => {
gate_feature_post!(
&self,
auto_traits,
gate_feature_post!(&self, decl_macro, i.span, msg);
}
- ast::ItemKind::TyAlias(box ast::TyAliasKind(_, _, _, Some(ref ty))) => {
+ ast::ItemKind::TyAlias(box ast::TyAlias { ty: Some(ref ty), .. }) => {
self.check_impl_trait(&ty)
}
ast::ExprKind::TryBlock(_) => {
gate_feature_post!(&self, try_blocks, e.span, "`try` expression is experimental");
}
- ast::ExprKind::Block(_, opt_label) => {
- if let Some(label) = opt_label {
- gate_feature_post!(
- &self,
- label_break_value,
- label.ident.span,
- "labels on blocks are unstable"
- );
- }
+ ast::ExprKind::Block(_, Some(label)) => {
+ gate_feature_post!(
+ &self,
+ label_break_value,
+ label.ident.span,
+ "labels on blocks are unstable"
+ );
}
_ => {}
}
fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
let is_fn = match i.kind {
ast::AssocItemKind::Fn(_) => true,
- ast::AssocItemKind::TyAlias(box ast::TyAliasKind(_, ref generics, _, ref ty)) => {
+ ast::AssocItemKind::TyAlias(box ast::TyAlias { ref generics, ref ty, .. }) => {
if let (Some(_), AssocCtxt::Trait) = (ty, ctxt) {
gate_feature_post!(
&self,
#![feature(iter_is_partitioned)]
#![feature(box_patterns)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
pub mod ast_validation;
pub mod feature_gate;
self.maybe_print_comment(span.lo());
self.print_outer_attributes(attrs);
match kind {
- ast::ForeignItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
- self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
+ ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
+ self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
}
ast::ForeignItemKind::Static(ty, mutbl, body) => {
let def = ast::Defaultness::Final;
self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
}
- ast::ForeignItemKind::TyAlias(box ast::TyAliasKind(def, generics, bounds, ty)) => {
- self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
+ ast::ForeignItemKind::TyAlias(box ast::TyAlias {
+ defaultness,
+ generics,
+ bounds,
+ ty,
+ }) => {
+ self.print_associated_type(
+ ident,
+ generics,
+ bounds,
+ ty.as_deref(),
+ vis,
+ *defaultness,
+ );
}
ast::ForeignItemKind::MacCall(m) => {
self.print_mac(m);
ast::ItemKind::Const(def, ref ty, ref body) => {
self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
}
- ast::ItemKind::Fn(box ast::FnKind(def, ref sig, ref gen, ref body)) => {
+ ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => {
let body = body.as_deref();
- self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs);
+ self.print_fn_full(
+ sig,
+ item.ident,
+ generics,
+ &item.vis,
+ defaultness,
+ body,
+ &item.attrs,
+ );
}
ast::ItemKind::Mod(unsafety, ref mod_kind) => {
self.head(self.to_string(|s| {
self.print_inline_asm(asm);
self.end();
}
- ast::ItemKind::TyAlias(box ast::TyAliasKind(def, ref generics, ref bounds, ref ty)) => {
+ ast::ItemKind::TyAlias(box ast::TyAlias {
+ defaultness,
+ ref generics,
+ ref bounds,
+ ref ty,
+ }) => {
let ty = ty.as_deref();
- self.print_associated_type(item.ident, generics, bounds, ty, &item.vis, def);
+ self.print_associated_type(
+ item.ident,
+ generics,
+ bounds,
+ ty,
+ &item.vis,
+ defaultness,
+ );
}
ast::ItemKind::Enum(ref enum_definition, ref params) => {
self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
self.head(visibility_qualified(&item.vis, "union"));
self.print_struct(struct_def, generics, item.ident, item.span, true);
}
- ast::ItemKind::Impl(box ast::ImplKind {
+ ast::ItemKind::Impl(box ast::Impl {
unsafety,
polarity,
defaultness,
}
self.bclose(item.span);
}
- ast::ItemKind::Trait(box ast::TraitKind(
+ ast::ItemKind::Trait(box ast::Trait {
is_auto,
unsafety,
ref generics,
ref bounds,
- ref trait_items,
- )) => {
+ ref items,
+ ..
+ }) => {
self.head("");
self.print_visibility(&item.vis);
self.print_unsafety(unsafety);
self.s.word(" ");
self.bopen();
self.print_inner_attributes(&item.attrs);
- for trait_item in trait_items {
+ for trait_item in items {
self.print_assoc_item(trait_item);
}
self.bclose(item.span);
}
}
- crate fn print_record_struct_body(
- &mut self,
- fields: &Vec<ast::FieldDef>,
- span: rustc_span::Span,
- ) {
+ crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
self.nbsp();
self.bopen();
self.hardbreak_if_not_bol();
self.maybe_print_comment(span.lo());
self.print_outer_attributes(attrs);
match kind {
- ast::AssocItemKind::Fn(box ast::FnKind(def, sig, gen, body)) => {
- self.print_fn_full(sig, ident, gen, vis, *def, body.as_deref(), attrs);
+ ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
+ self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
}
ast::AssocItemKind::Const(def, ty, body) => {
self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
}
- ast::AssocItemKind::TyAlias(box ast::TyAliasKind(def, generics, bounds, ty)) => {
- self.print_associated_type(ident, generics, bounds, ty.as_deref(), vis, *def);
+ ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
+ self.print_associated_type(
+ ident,
+ generics,
+ bounds,
+ ty.as_deref(),
+ vis,
+ *defaultness,
+ );
}
ast::AssocItemKind::MacCall(m) => {
self.print_mac(m);
use std::fmt;
use std::ops::Index;
-crate struct BorrowSet<'tcx> {
+pub struct BorrowSet<'tcx> {
/// The fundamental map relating bitvector indexes to the borrows
/// in the MIR. Each borrow is also uniquely identified in the MIR
/// by the `Location` of the assignment statement in which it
/// appears on the right hand side. Thus the location is the map
/// key, and its position in the map corresponds to `BorrowIndex`.
- crate location_map: FxIndexMap<Location, BorrowData<'tcx>>,
+ pub location_map: FxIndexMap<Location, BorrowData<'tcx>>,
/// Locations which activate borrows.
/// NOTE: a given location may activate more than one borrow in the future
/// when more general two-phase borrow support is introduced, but for now we
/// only need to store one borrow index.
- crate activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
+ pub activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
/// Map from local to all the borrows on that local.
- crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
+ pub local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
crate locals_state_at_exit: LocalsStateAtExit,
}
/// Location where a two-phase borrow is activated, if a borrow
/// is in fact a two-phase borrow.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-crate enum TwoPhaseActivation {
+pub enum TwoPhaseActivation {
NotTwoPhase,
NotActivated,
ActivatedAt(Location),
}
#[derive(Debug, Clone)]
-crate struct BorrowData<'tcx> {
+pub struct BorrowData<'tcx> {
/// Location where the borrow reservation starts.
/// In many cases, this will be equal to the activation location but not always.
- crate reserve_location: Location,
+ pub reserve_location: Location,
/// Location where the borrow is activated.
- crate activation_location: TwoPhaseActivation,
+ pub activation_location: TwoPhaseActivation,
/// What kind of borrow this is
- crate kind: mir::BorrowKind,
+ pub kind: mir::BorrowKind,
/// The region for which this borrow is live
- crate region: RegionVid,
+ pub region: RegionVid,
/// Place from which we are borrowing
- crate borrowed_place: mir::Place<'tcx>,
+ pub borrowed_place: mir::Place<'tcx>,
/// Place to which the borrow was stored
- crate assigned_place: mir::Place<'tcx>,
+ pub assigned_place: mir::Place<'tcx>,
}
impl<'tcx> fmt::Display for BorrowData<'tcx> {
}
}
-crate enum LocalsStateAtExit {
+pub enum LocalsStateAtExit {
AllAreInvalidated,
SomeAreInvalidated { has_storage_dead_or_moved: BitSet<Local> },
}
// We generally shouldn't have errors here because the query was
// already run, but there's no point using `delay_span_bug`
// when we're going to emit an error here anyway.
- let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);
+ let _errors = fulfill_cx.select_all_or_error(infcx);
let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
debug!("{:#?}", region_constraints);
let param = generics.type_param(¶m_ty, tcx);
if let Some(generics) = tcx
.hir()
- .get_generics(tcx.closure_base_def_id(self.mir_def_id().to_def_id()))
+ .get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id()))
{
suggest_constraining_type_param(
tcx,
impl BorrowExplanation {
pub(crate) fn is_explained(&self) -> bool {
- match self {
- BorrowExplanation::Unexplained => false,
- _ => true,
- }
+ !matches!(self, BorrowExplanation::Unexplained)
}
pub(crate) fn add_explanation_to_diagnostic<'tcx>(
&self,
#![feature(bool_to_option)]
#![feature(box_patterns)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(crate_visibility_modifier)]
#![feature(format_args_capture)]
#![feature(in_band_lifetimes)]
#![feature(trusted_step)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_middle;
use self::path_utils::*;
-mod borrow_set;
+pub mod borrow_set;
mod borrowck_errors;
mod constraint_generation;
mod constraints;
errors_buffer: &mut Vec<Diagnostic>,
) {
let tcx = infcx.tcx;
- let base_def_id = tcx.closure_base_def_id(body.source.def_id());
+ let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
if !tcx.has_attr(base_def_id, sym::rustc_regions) {
return;
}
// to store those. Otherwise, we'll pass in `None` to the
// functions below, which will trigger them to report errors
// eagerly.
- let mut outlives_requirements = infcx.tcx.is_closure(mir_def_id).then(Vec::new);
+ let mut outlives_requirements = infcx.tcx.is_typeck_child(mir_def_id).then(Vec::new);
self.check_type_tests(infcx, body, outlives_requirements.as_mut(), &mut errors_buffer);
_ => constraint_sup_scc != target_scc,
}
} else {
- match categorized_path[*i].category {
+ !matches!(
+ categorized_path[*i].category,
ConstraintCategory::OpaqueType
- | ConstraintCategory::Boring
- | ConstraintCategory::BoringNoLocation
- | ConstraintCategory::Internal
- | ConstraintCategory::Predicate(_) => false,
- _ => true,
- }
+ | ConstraintCategory::Boring
+ | ConstraintCategory::BoringNoLocation
+ | ConstraintCategory::Internal
+ | ConstraintCategory::Predicate(_)
+ )
}
};
tcx,
closure_substs,
self.num_external_vids,
- tcx.closure_base_def_id(closure_def_id),
+ tcx.typeck_root_def_id(closure_def_id),
);
debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem;
use rustc_index::vec::{Idx, IndexVec};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::VariantIdx;
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
// If the region is live at at least one location in the promoted MIR,
// then add a liveness constraint to the main MIR for this region
// at the location provided as an argument to this method
- if let Some(_) = liveness_constraints.get_elements(region).next() {
+ if liveness_constraints.get_elements(region).next().is_some() {
self.cx
.borrowck_context
.constraints
// though.
let category = match place.as_local() {
Some(RETURN_PLACE) => {
- if let BorrowCheckContext {
- universal_regions:
- UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
- ..
- } = self.borrowck_context
- {
- if tcx.is_static(*def_id) {
+ let defining_ty = &self.borrowck_context.universal_regions.defining_ty;
+ if defining_ty.is_const() {
+ if tcx.is_static(defining_ty.def_id()) {
ConstraintCategory::UseAsStatic
} else {
ConstraintCategory::UseAsConst
}
}
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
+ self.check_operand(discr, term_location);
+
let discr_ty = discr.ty(body, tcx);
if let Err(terr) = self.sub_types(
discr_ty,
// FIXME: check the values
}
TerminatorKind::Call { ref func, ref args, ref destination, from_hir_call, .. } => {
+ self.check_operand(func, term_location);
+ for arg in args {
+ self.check_operand(arg, term_location);
+ }
+
let func_ty = func.ty(body, tcx);
debug!("check_terminator: call, func_ty={:?}", func_ty);
let sig = match func_ty.kind() {
self.check_call_inputs(body, term, &sig, args, term_location, from_hir_call);
}
TerminatorKind::Assert { ref cond, ref msg, .. } => {
+ self.check_operand(cond, term_location);
+
let cond_ty = cond.ty(body, tcx);
if cond_ty != tcx.types.bool {
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
}
}
TerminatorKind::Yield { ref value, .. } => {
+ self.check_operand(value, term_location);
+
let value_ty = value.ty(body, tcx);
match body.yield_ty() {
None => span_mirbug!(self, term, "yield in non-generator"),
Some(RETURN_PLACE) => {
if let BorrowCheckContext {
universal_regions:
- UniversalRegions { defining_ty: DefiningTy::Const(def_id, _), .. },
+ UniversalRegions {
+ defining_ty:
+ DefiningTy::Const(def_id, _)
+ | DefiningTy::InlineConst(def_id, _),
+ ..
+ },
..
} = self.borrowck_context
{
}
}
+ fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
+ if let Operand::Constant(constant) = op {
+ let maybe_uneval = match constant.literal {
+ ConstantKind::Ty(ct) => match ct.val {
+ ty::ConstKind::Unevaluated(uv) => Some(uv),
+ _ => None,
+ },
+ _ => None,
+ };
+ if let Some(uv) = maybe_uneval {
+ if uv.promoted.is_none() {
+ let tcx = self.tcx();
+ let def_id = uv.def.def_id_for_type_of();
+ if tcx.def_kind(def_id) == DefKind::InlineConst {
+ let predicates = self.prove_closure_bounds(
+ tcx,
+ def_id.expect_local(),
+ uv.substs(tcx),
+ location,
+ );
+ self.normalize_and_prove_instantiated_predicates(
+ def_id,
+ predicates,
+ location.to_locations(),
+ );
+ }
+ }
+ }
+ }
+ }
+
fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
let tcx = self.tcx();
match rvalue {
Rvalue::Aggregate(ak, ops) => {
+ for op in ops {
+ self.check_operand(op, location);
+ }
self.check_aggregate_rvalue(&body, rvalue, ak, ops, location)
}
Rvalue::Repeat(operand, len) => {
+ self.check_operand(operand, location);
+
// If the length cannot be evaluated we must assume that the length can be larger
// than 1.
// If the length is larger than 1, the repeat expression will need to copy the
}
}
- Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
+ Rvalue::NullaryOp(_, ty) => {
+ let trait_ref = ty::TraitRef {
+ def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
+ substs: tcx.mk_substs_trait(ty, &[]),
+ };
+
+ self.prove_trait_ref(
+ trait_ref,
+ location.to_locations(),
+ ConstraintCategory::SizedBound,
+ );
+ }
+
+ Rvalue::ShallowInitBox(operand, ty) => {
+ self.check_operand(operand, location);
+
let trait_ref = ty::TraitRef {
def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
substs: tcx.mk_substs_trait(ty, &[]),
}
Rvalue::Cast(cast_kind, op, ty) => {
+ self.check_operand(op, location);
+
match cast_kind {
CastKind::Pointer(PointerCast::ReifyFnPointer) => {
let fn_sig = op.ty(body, tcx).fn_sig(tcx);
BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge,
box (left, right),
) => {
+ self.check_operand(left, location);
+ self.check_operand(right, location);
+
let ty_left = left.ty(body, tcx);
match ty_left.kind() {
// Types with regions are comparable if they have a common super-type.
}
}
+ Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => {
+ self.check_operand(operand, location);
+ }
+
+ Rvalue::BinaryOp(_, box (left, right))
+ | Rvalue::CheckedBinaryOp(_, box (left, right)) => {
+ self.check_operand(left, location);
+ self.check_operand(right, location);
+ }
+
Rvalue::AddressOf(..)
| Rvalue::ThreadLocalRef(..)
- | Rvalue::Use(..)
| Rvalue::Len(..)
- | Rvalue::BinaryOp(..)
- | Rvalue::CheckedBinaryOp(..)
- | Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..) => {}
}
}
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
use std::iter;
use crate::nll::ToRegionVid;
/// is that it has no inputs and a single return value, which is
/// the value of the constant.
Const(DefId, SubstsRef<'tcx>),
+
+ /// The MIR represents an inline const. The signature has no inputs and a
+ /// single return value found via `InlineConstSubsts::ty`.
+ InlineConst(DefId, SubstsRef<'tcx>),
}
impl<'tcx> DefiningTy<'tcx> {
DefiningTy::Generator(_, substs, _) => {
Either::Right(Either::Left(substs.as_generator().upvar_tys()))
}
- DefiningTy::FnDef(..) | DefiningTy::Const(..) => {
+ DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => {
Either::Right(Either::Right(iter::empty()))
}
}
pub fn implicit_inputs(self) -> usize {
match self {
DefiningTy::Closure(..) | DefiningTy::Generator(..) => 1,
- DefiningTy::FnDef(..) | DefiningTy::Const(..) => 0,
+ DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0,
}
}
pub fn is_fn_def(&self) -> bool {
- match *self {
- DefiningTy::FnDef(..) => true,
- _ => false,
- }
+ matches!(*self, DefiningTy::FnDef(..))
}
pub fn is_const(&self) -> bool {
- match *self {
- DefiningTy::Const(..) => true,
- _ => false,
- }
+ matches!(*self, DefiningTy::Const(..) | DefiningTy::InlineConst(..))
}
pub fn def_id(&self) -> DefId {
DefiningTy::Closure(def_id, ..)
| DefiningTy::Generator(def_id, ..)
| DefiningTy::FnDef(def_id, ..)
- | DefiningTy::Const(def_id, ..) => def_id,
+ | DefiningTy::Const(def_id, ..)
+ | DefiningTy::InlineConst(def_id, ..) => def_id,
}
}
}
tcx: TyCtxt<'tcx>,
closure_substs: SubstsRef<'tcx>,
expected_num_vars: usize,
- closure_base_def_id: DefId,
+ typeck_root_def_id: DefId,
) -> IndexVec<RegionVid, ty::Region<'tcx>> {
let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
region_mapping.push(tcx.lifetimes.re_static);
region_mapping.push(fr);
});
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
region_mapping.push(r);
});
// tests, and the resulting print-outs include def-ids
// and other things that are not stable across tests!
// So we just include the region-vid. Annoying.
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
});
}
// FIXME: As above, we'd like to print out the region
// `r` but doing so is not stable across architectures
// and so forth.
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- for_each_late_bound_region_defined_on(tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
});
}
tcx.def_path_str_with_substs(def_id, substs),
));
}
+ DefiningTy::InlineConst(def_id, substs) => {
+ err.note(&format!(
+ "defining inline constant type: {}",
+ tcx.def_path_str_with_substs(def_id, substs),
+ ));
+ }
}
}
}
let mut indices = self.compute_indices(fr_static, defining_ty);
debug!("build: indices={:?}", indices);
- let closure_base_def_id = self.infcx.tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+ let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
// If this is a closure or generator, then the late-bound regions from the enclosing
// function are actually external regions to us. For example, here, 'a is not local
// fn foo<'a>() {
// let c = || { let x: &'a u32 = ...; }
// }
- if self.mir_def.did.to_def_id() != closure_base_def_id {
+ if self.mir_def.did.to_def_id() != typeck_root_def_id {
self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
}
);
// Converse of above, if this is a function then the late-bound regions declared on its
// signature are local to the fn.
- if self.mir_def.did.to_def_id() == closure_base_def_id {
+ if self.mir_def.did.to_def_id() == typeck_root_def_id {
self.infcx
.replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
}
/// see `DefiningTy` for details.
fn defining_ty(&self) -> DefiningTy<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
+ let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
match tcx.hir().body_owner_kind(self.mir_hir_id) {
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
- let defining_ty = if self.mir_def.did.to_def_id() == closure_base_def_id {
- tcx.type_of(closure_base_def_id)
+ let defining_ty = if self.mir_def.did.to_def_id() == typeck_root_def_id {
+ tcx.type_of(typeck_root_def_id)
} else {
let tables = tcx.typeck(self.mir_def.did);
tables.node_type(self.mir_hir_id)
}
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
- assert_eq!(self.mir_def.did.to_def_id(), closure_base_def_id);
- let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
- let substs =
- self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
- DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+ let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
+ if self.mir_def.did.to_def_id() == typeck_root_def_id {
+ let substs =
+ self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
+ DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+ } else {
+ let ty = tcx.typeck(self.mir_def.did).node_type(self.mir_hir_id);
+ let substs = InlineConstSubsts::new(
+ tcx,
+ InlineConstSubstsParts { parent_substs: identity_substs, ty },
+ )
+ .substs;
+ let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs);
+ DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs)
+ }
}
}
}
defining_ty: DefiningTy<'tcx>,
) -> UniversalRegionIndices<'tcx> {
let tcx = self.infcx.tcx;
- let closure_base_def_id = tcx.closure_base_def_id(self.mir_def.did.to_def_id());
- let identity_substs = InternalSubsts::identity_for_item(tcx, closure_base_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
+ let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
let fr_substs = match defining_ty {
- DefiningTy::Closure(_, ref substs) | DefiningTy::Generator(_, ref substs, _) => {
+ DefiningTy::Closure(_, ref substs)
+ | DefiningTy::Generator(_, ref substs, _)
+ | DefiningTy::InlineConst(_, ref substs) => {
// In the case of closures, we rely on the fact that
// the first N elements in the ClosureSubsts are
- // inherited from the `closure_base_def_id`.
+ // inherited from the `typeck_root_def_id`.
// Therefore, when we zip together (below) with
// `identity_substs`, we will get only those regions
// that correspond to early-bound regions declared on
- // the `closure_base_def_id`.
+ // the `typeck_root_def_id`.
assert!(substs.len() >= identity_substs.len());
assert_eq!(substs.regions().count(), identity_substs.regions().count());
substs
let ty = indices.fold_to_region_vids(tcx, ty);
ty::Binder::dummy(tcx.intern_type_list(&[ty]))
}
+
+ DefiningTy::InlineConst(def_id, substs) => {
+ assert_eq!(self.mir_def.did.to_def_id(), def_id);
+ let ty = substs.as_inline_const().ty();
+ ty::Binder::dummy(tcx.intern_type_list(&[ty]))
+ }
}
}
}
indices: &mut UniversalRegionIndices<'tcx>,
) {
debug!("replace_late_bound_regions_with_nll_infer_vars(mir_def_id={:?})", mir_def_id);
- let closure_base_def_id = self.tcx.closure_base_def_id(mir_def_id.to_def_id());
- for_each_late_bound_region_defined_on(self.tcx, closure_base_def_id, |r| {
+ let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
+ for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
debug!("replace_late_bound_regions_with_nll_infer_vars: r={:?}", r);
if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR);
if let Some(snippet) = &template_snippet {
if let Some(pos) = snippet.find(needle) {
let end = pos
- + &snippet[pos..]
+ + snippet[pos..]
.find(|c| matches!(c, '\n' | ';' | '\\' | '"'))
.unwrap_or(snippet[pos..].len() - 1);
let inner = InnerSpan::new(pos, end);
tokens: None,
},
attrs: Vec::new(),
- kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAliasKind(
- ast::Defaultness::Final,
- Generics::default(),
- Vec::new(),
- Some(type_def.to_ty(cx, self.span, type_ident, generics)),
- ))),
+ kind: ast::AssocItemKind::TyAlias(Box::new(ast::TyAlias {
+ defaultness: ast::Defaultness::Final,
+ generics: Generics::default(),
+ bounds: Vec::new(),
+ ty: Some(type_def.to_ty(cx, self.span, type_ident, generics)),
+ })),
tokens: None,
})
});
self.span,
Ident::empty(),
a,
- ast::ItemKind::Impl(Box::new(ast::ImplKind {
+ ast::ItemKind::Impl(Box::new(ast::Impl {
unsafety,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
decl: fn_decl,
span: trait_.span,
};
- let def = ast::Defaultness::Final;
+ let defaultness = ast::Defaultness::Final;
// Create the method.
P(ast::AssocItem {
tokens: None,
},
ident: method_ident,
- kind: ast::AssocItemKind::Fn(Box::new(ast::FnKind(
- def,
+ kind: ast::AssocItemKind::Fn(Box::new(ast::Fn {
+ defaultness,
sig,
- fn_generics,
- Some(body_block),
- ))),
+ generics: fn_generics,
+ body: Some(body_block),
+ })),
tokens: None,
})
}
use rustc_ast as ast;
use rustc_ast::ptr::P;
-use rustc_ast::{ImplKind, ItemKind, MetaItem};
+use rustc_ast::{Impl, ItemKind, MetaItem};
use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, MultiItemModifier};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;
span,
Ident::empty(),
attrs,
- ItemKind::Impl(Box::new(ImplKind {
+ ItemKind::Impl(Box::new(Impl {
unsafety: ast::Unsafe::No,
polarity: ast::ImplPolarity::Positive,
defaultness: ast::Defaultness::Final,
/// Actually builds the expression which the format_args! block will be
/// expanded to.
fn into_expr(self) -> P<ast::Expr> {
- let mut locals =
- Vec::with_capacity((0..self.args.len()).map(|i| self.arg_unique_types[i].len()).sum());
- let mut counts = Vec::with_capacity(self.count_args.len());
- let mut pats = Vec::with_capacity(self.args.len());
+ let mut args = Vec::with_capacity(
+ self.arg_unique_types.iter().map(|v| v.len()).sum::<usize>() + self.count_args.len(),
+ );
let mut heads = Vec::with_capacity(self.args.len());
- let names_pos: Vec<_> = (0..self.args.len())
- .map(|i| Ident::from_str_and_span(&format!("arg{}", i), self.macsp))
- .collect();
-
// First, build up the static array which will become our precompiled
// format "string"
let pieces = self.ecx.expr_vec_slice(self.fmtsp, self.str_pieces);
// of each variable because we don't want to move out of the arguments
// passed to this function.
for (i, e) in self.args.into_iter().enumerate() {
- let name = names_pos[i];
- let span = self.ecx.with_def_site_ctxt(e.span);
- pats.push(self.ecx.pat_ident(span, name));
for arg_ty in self.arg_unique_types[i].iter() {
- locals.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, name));
+ args.push(Context::format_arg(self.ecx, self.macsp, e.span, arg_ty, i));
}
heads.push(self.ecx.expr_addr_of(e.span, e));
}
Exact(i) => i,
_ => panic!("should never happen"),
};
- let name = names_pos[index];
let span = spans_pos[index];
- counts.push(Context::format_arg(self.ecx, self.macsp, span, &Count, name));
+ args.push(Context::format_arg(self.ecx, self.macsp, span, &Count, index));
}
- // Now create a vector containing all the arguments
- let args = locals.into_iter().chain(counts.into_iter());
-
- let args_array = self.ecx.expr_vec(self.macsp, args.collect());
+ let args_array = self.ecx.expr_vec(self.macsp, args);
// Constructs an AST equivalent to:
//
// But the nested match expression is proved to perform not as well
// as series of let's; the first approach does.
let args_match = {
- let pat = self.ecx.pat_tuple(self.macsp, pats);
+ let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::_args, self.macsp));
let arm = self.ecx.arm(self.macsp, pat, args_array);
let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
self.ecx.expr_match(self.macsp, head, vec![arm])
macsp: Span,
mut sp: Span,
ty: &ArgumentType,
- arg: Ident,
+ arg_index: usize,
) -> P<ast::Expr> {
sp = ecx.with_def_site_ctxt(sp);
- let arg = ecx.expr_ident(sp, arg);
+ let arg = ecx.expr_ident(sp, Ident::new(sym::_args, sp));
+ let arg = ecx.expr(sp, ast::ExprKind::Field(arg, Ident::new(sym::integer(arg_index), sp)));
let trait_ = match *ty {
Placeholder(trait_) if trait_ == "<invalid>" => return DummyResult::raw_expr(sp, true),
Placeholder(trait_) => trait_,
};
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, Attribute, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
-use rustc_ast::{FnKind, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
+use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty));
let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() };
let sig = FnSig { decl, header, span: self.span };
- let block = Some(self.cx.block_expr(output_expr));
- let kind = ItemKind::Fn(Box::new(FnKind(
- ast::Defaultness::Final,
+ let body = Some(self.cx.block_expr(output_expr));
+ let kind = ItemKind::Fn(Box::new(Fn {
+ defaultness: ast::Defaultness::Final,
sig,
- Generics::default(),
- block,
- )));
+ generics: Generics::default(),
+ body,
+ }));
let item = self.cx.item(
self.span,
Ident::from_str_and_span(&self.kind.fn_name(method.name), self.span),
#![feature(proc_macro_internals)]
#![feature(proc_macro_quote)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
extern crate proc_macro;
fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic);
let sd = &cx.sess.parse_sess.span_diagnostic;
- if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, ref generics, _)) = i.kind {
+ if let ast::ItemKind::Fn(box ast::Fn { ref sig, ref generics, .. }) = i.kind {
if let ast::Unsafe::Yes(span) = sig.header.unsafety {
sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
.span_label(span, "`unsafe` because of this")
}
fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
- let has_sig = if let ast::ItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) = i.kind {
+ let has_sig = if let ast::ItemKind::Fn(box ast::Fn { ref sig, .. }) = i.kind {
// N.B., inadequate check, but we're running
// well before resolve, can't get too deep.
sig.decl.inputs.len() == 1
let decl = ecx.fn_decl(vec![], ast::FnRetTy::Ty(main_ret_ty));
let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp };
- let def = ast::Defaultness::Final;
- let main = ast::ItemKind::Fn(Box::new(ast::FnKind(
- def,
+ let defaultness = ast::Defaultness::Final;
+ let main = ast::ItemKind::Fn(Box::new(ast::Fn {
+ defaultness,
sig,
- ast::Generics::default(),
- Some(main_body),
- )));
+ generics: ast::Generics::default(),
+ body: Some(main_body),
+ }));
// Honor the reexport_test_harness_main attribute
let main_id = match cx.reexport_test_harness_main {
true
}
- fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span]) {
+ fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span], _instance: Instance<'_>) {
let asm_arch = self.tcx.sess.asm_arch.unwrap();
let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
// TODO(antoyo)
}
+ fn type_metadata(&mut self, _function: RValue<'gcc>, _typeid: String) {
+ // Unsupported.
+ }
+
+ fn typeid_metadata(&mut self, _typeid: String) -> RValue<'gcc> {
+ // Unsupported.
+ self.context.new_rvalue_from_int(self.int_type, 0)
+ }
+
+
fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
self.store_with_flags(val, ptr, align, MemFlags::empty())
}
// TODO(antoyo)
}
+ fn type_test(&mut self, _pointer: Self::Value, _typeid: Self::Value) -> Self::Value {
+ // Unsupported.
+ self.context.new_rvalue_from_int(self.int_type, 0)
+ }
+
fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
unimplemented!();
}
use crate::builder::Builder;
use crate::context::CodegenCx;
use crate::llvm::{self, AttributePlace};
-use crate::llvm_util;
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
use crate::value::Value;
}
fn should_use_mutable_noalias(cx: &CodegenCx<'_, '_>) -> bool {
- // LLVM prior to version 12 has known miscompiles in the presence of
- // noalias attributes (see #54878). Only enable mutable noalias by
- // default for versions we believe to be safe.
- cx.tcx
- .sess
- .opts
- .debugging_opts
- .mutable_noalias
- .unwrap_or_else(|| llvm_util::get_version() >= (12, 0, 0))
+ // LLVM prior to version 12 had known miscompiles in the presence of
+ // noalias attributes (see #54878), but we don't support earlier
+ // versions at all anymore. We now enable mutable noalias by default.
+ cx.tcx.sess.opts.debugging_opts.mutable_noalias.unwrap_or(true)
}
impl ArgAttributesExt for ArgAttributes {
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::{bug, span_bug};
+use rustc_middle::{bug, span_bug, ty::Instance};
use rustc_span::{Pos, Span, Symbol};
use rustc_target::abi::*;
use rustc_target::asm::*;
operands: &[InlineAsmOperandRef<'tcx, Self>],
options: InlineAsmOptions,
line_spans: &[Span],
+ instance: Instance<'_>,
) {
let asm_arch = self.tcx.sess.asm_arch.unwrap();
let is_target_supported = |reg_class: InlineAsmRegClass| {
for &(_, feature) in reg_class.supported_types(asm_arch) {
if let Some(feature) = feature {
- if self.tcx.sess.target_features.contains(&Symbol::intern(feature))
+ let codegen_fn_attrs = self.tcx.codegen_fn_attrs(instance.def_id());
+ let feature_name = Symbol::intern(feature);
+ if self.tcx.sess.target_features.contains(&feature_name)
+ || codegen_fn_attrs.target_features.contains(&feature_name)
{
return true;
}
let ffunction_sections =
sess.opts.debugging_opts.function_sections.unwrap_or(sess.target.function_sections);
let fdata_sections = ffunction_sections;
+ let funique_section_names = !sess.opts.debugging_opts.no_unique_section_names;
let code_model = to_llvm_code_model(sess.code_model());
use_softfp,
ffunction_sections,
fdata_sections,
+ funique_section_names,
trap_unreachable,
singlethread,
asm_comments,
cookie = 0;
}
let level = match level {
- llvm::DiagnosticLevel::Error => Level::Error,
+ llvm::DiagnosticLevel::Error => Level::Error { lint: false },
llvm::DiagnosticLevel::Warning => Level::Warning,
llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
};
}
}
+ fn type_metadata(&mut self, function: &'ll Value, typeid: String) {
+ let typeid_metadata = self.typeid_metadata(typeid);
+ let v = [self.const_usize(0), typeid_metadata];
+ unsafe {
+ llvm::LLVMGlobalSetMetadata(
+ function,
+ llvm::MD_type as c_uint,
+ llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
+ self.cx.llcx,
+ v.as_ptr(),
+ v.len() as c_uint,
+ )),
+ )
+ }
+ }
+
+ fn typeid_metadata(&mut self, typeid: String) -> Self::Value {
+ unsafe {
+ llvm::LLVMMDStringInContext(
+ self.cx.llcx,
+ typeid.as_ptr() as *const c_char,
+ typeid.as_bytes().len() as c_uint,
+ )
+ }
+ }
+
fn store(&mut self, val: &'ll Value, ptr: &'ll Value, align: Align) -> &'ll Value {
self.store_with_flags(val, ptr, align, MemFlags::empty())
}
}
fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
- if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
+ if !self.fptoint_sat_broken_in_llvm() {
let src_ty = self.cx.val_ty(val);
let float_width = self.cx.float_width(src_ty);
let int_width = self.cx.int_width(dest_ty);
}
fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
- if llvm_util::get_version() >= (12, 0, 0) && !self.fptoint_sat_broken_in_llvm() {
+ if !self.fptoint_sat_broken_in_llvm() {
let src_ty = self.cx.val_ty(val);
let float_width = self.cx.float_width(src_ty);
let int_width = self.cx.int_width(dest_ty);
let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
let mut target_data_layout = sess.target.data_layout.clone();
- if llvm_util::get_version() < (12, 0, 0) && sess.target.arch == "powerpc64" {
- target_data_layout = target_data_layout.replace("-v256:256:256-v512:512:512", "");
- }
if llvm_util::get_version() < (13, 0, 0) {
if sess.target.arch == "powerpc64" {
target_data_layout = target_data_layout.replace("-S128", "");
llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
}
+ if sess.is_sanitizer_cfi_enabled() {
+ // FIXME(rcvalle): Add support for non canonical jump tables.
+ let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast();
+ // FIXME(rcvalle): Add it with Override behavior flag--LLVMRustAddModuleFlag adds it with
+ // Warning behavior flag. Add support for specifying the behavior flag to
+ // LLVMRustAddModuleFlag.
+ llvm::LLVMRustAddModuleFlag(llmod, canonical_jump_tables, 1);
+ }
+
// Control Flow Guard is currently only supported by the MSVC linker on Windows.
if sess.target.is_like_msvc {
match sess.opts.cg.control_flow_guard {
ifn!("llvm.instrprof.increment", fn(i8p, t_i64, t_i32, t_i32) -> void);
}
+ ifn!("llvm.type.test", fn(i8p, self.type_metadata()) -> i1);
+
if self.sess().opts.debuginfo != DebugInfo::None {
ifn!("llvm.dbg.declare", fn(self.type_metadata(), self.type_metadata()) -> void);
ifn!("llvm.dbg.value", fn(self.type_metadata(), t_i64, self.type_metadata()) -> void);
type_names::push_item_name(self.tcx(), def_id, false, &mut name);
// Find the enclosing function, in case this is a closure.
- let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
+ let enclosing_fn_def_id = self.tcx().typeck_root_def_id(def_id);
// Get_template_parameters() will append a `<...>` clause to the function
// name if necessary.
}
}
+ fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value {
+ // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time
+ // optimization pass replaces calls to this intrinsic with code to test type membership.
+ let i8p_ty = self.type_i8p();
+ let bitcast = self.bitcast(pointer, i8p_ty);
+ self.call_intrinsic("llvm.type.test", &[bitcast, typeid])
+ }
+
fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
self.call_intrinsic("llvm.va_start", &[va_list])
}
#![feature(iter_zip)]
#![feature(nll)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
use back::write::{create_informational_target_machine, create_target_machine};
#[derive(Clone)]
pub struct LlvmCodegenBackend(());
+struct TimeTraceProfiler {
+ enabled: bool,
+}
+
+impl TimeTraceProfiler {
+ fn new(enabled: bool) -> Self {
+ if enabled {
+ unsafe { llvm::LLVMTimeTraceProfilerInitialize() }
+ }
+ TimeTraceProfiler { enabled }
+ }
+}
+
+impl Drop for TimeTraceProfiler {
+ fn drop(&mut self) {
+ if self.enabled {
+ unsafe { llvm::LLVMTimeTraceProfilerFinishThread() }
+ }
+ }
+}
+
impl ExtraBackendMethods for LlvmCodegenBackend {
fn new_metadata(&self, tcx: TyCtxt<'_>, mod_name: &str) -> ModuleLlvm {
ModuleLlvm::new_metadata(tcx, mod_name)
fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> {
llvm_util::tune_cpu(sess)
}
+
+ fn spawn_thread<F, T>(time_trace: bool, f: F) -> std::thread::JoinHandle<T>
+ where
+ F: FnOnce() -> T,
+ F: Send + 'static,
+ T: Send + 'static,
+ {
+ std::thread::spawn(move || {
+ let _profiler = TimeTraceProfiler::new(time_trace);
+ f()
+ })
+ }
+
+ fn spawn_named_thread<F, T>(
+ time_trace: bool,
+ name: String,
+ f: F,
+ ) -> std::io::Result<std::thread::JoinHandle<T>>
+ where
+ F: FnOnce() -> T,
+ F: Send + 'static,
+ T: Send + 'static,
+ {
+ std::thread::Builder::new().name(name).spawn(move || {
+ let _profiler = TimeTraceProfiler::new(time_trace);
+ f()
+ })
+ }
}
impl WriteBackendMethods for LlvmCodegenBackend {
MD_nontemporal = 9,
MD_mem_parallel_loop_access = 10,
MD_nonnull = 11,
+ MD_type = 19,
}
/// LLVMRustAsmDialect
pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t);
pub fn LLVMReplaceAllUsesWith(OldVal: &'a Value, NewVal: &'a Value);
pub fn LLVMSetMetadata(Val: &'a Value, KindID: c_uint, Node: &'a Value);
+ pub fn LLVMGlobalSetMetadata(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata);
+ pub fn LLVMValueAsMetadata(Node: &'a Value) -> &Metadata;
// Operations on constants of any type
pub fn LLVMConstNull(Ty: &Type) -> &Value;
pub fn LLVMTimeTraceProfilerInitialize();
+ pub fn LLVMTimeTraceProfilerFinishThread();
+
pub fn LLVMTimeTraceProfilerFinish(FileName: *const c_char);
pub fn LLVMAddAnalysisPasses(T: &'a TargetMachine, PM: &PassManager<'a>);
pub fn LLVMDisposeMessage(message: *mut c_char);
- pub fn LLVMStartMultithreaded() -> Bool;
+ pub fn LLVMIsMultithreaded() -> Bool;
/// Returns a string describing the last error caused by an LLVMRust* call.
pub fn LLVMRustGetLastError() -> *const c_char;
UseSoftFP: bool,
FunctionSections: bool,
DataSections: bool,
+ UniqueSectionNames: bool,
TrapUnreachable: bool,
Singlethread: bool,
AsmComments: bool,
use std::ptr;
use std::slice;
use std::str;
-use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;
-static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();
pub(crate) fn init(sess: &Session) {
unsafe {
// Before we touch LLVM, make sure that multithreading is enabled.
+ if llvm::LLVMIsMultithreaded() != 1 {
+ bug!("LLVM compiled without support for threads");
+ }
INIT.call_once(|| {
- if llvm::LLVMStartMultithreaded() != 1 {
- // use an extra bool to make sure that all future usage of LLVM
- // cannot proceed despite the Once not running more than once.
- POISONED.store(true, Ordering::SeqCst);
- }
-
configure_llvm(sess);
});
-
- if POISONED.load(Ordering::SeqCst) {
- bug!("couldn't enable multi-threaded LLVM");
- }
}
}
fn require_inited() {
- INIT.call_once(|| bug!("llvm is not initialized"));
- if POISONED.load(Ordering::SeqCst) {
- bug!("couldn't enable multi-threaded LLVM");
+ if !INIT.is_completed() {
+ bug!("LLVM is not initialized");
}
}
}
if sess.opts.debugging_opts.llvm_time_trace {
- // time-trace is not thread safe and running it in parallel will cause seg faults.
- if !sess.opts.debugging_opts.no_parallel_llvm {
- bug!("`-Z llvm-time-trace` requires `-Z no-parallel-llvm")
- }
-
llvm::LLVMTimeTraceProfilerInitialize();
}
("aarch64", "dpb2") => vec!["ccdp"],
("aarch64", "frintts") => vec!["fptoint"],
("aarch64", "fcma") => vec!["complxnum"],
+ ("aarch64", "pmuv3") => vec!["perfmon"],
(_, s) => vec![s],
}
}
// -Ctarget-features
features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
- // FIXME: Move outline-atomics to target definition when earliest supported LLVM is 12.
- if get_version() >= (12, 0, 0) && sess.target.llvm_target.contains("aarch64-unknown-linux") {
- features.push("+outline-atomics".to_string());
- }
-
features
}
}
fn link_sanitizer_runtime(sess: &Session, linker: &mut dyn Linker, name: &str) {
- fn find_sanitizer_runtime(sess: &Session, filename: &String) -> PathBuf {
+ fn find_sanitizer_runtime(sess: &Session, filename: &str) -> PathBuf {
let session_tlib =
filesearch::make_target_lib_path(&sess.sysroot, sess.opts.target_triple.triple());
- let path = session_tlib.join(&filename);
+ let path = session_tlib.join(filename);
if path.exists() {
return session_tlib;
} else {
use rustc_middle::middle::exported_symbols::{
metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::Instance;
use rustc_middle::ty::{SymbolName, TyCtxt};
providers.wasm_import_module_map = wasm_import_module_map;
}
-pub fn provide_extern(providers: &mut Providers) {
+pub fn provide_extern(providers: &mut ExternProviders) {
providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern;
providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider;
}
pub no_landing_pads: bool,
pub save_temps: bool,
pub fewer_names: bool,
+ pub time_trace: bool,
pub exported_symbols: Option<Arc<ExportedSymbols>>,
pub opts: Arc<config::Options>,
pub crate_types: Vec<CrateType>,
no_landing_pads: sess.panic_strategy() == PanicStrategy::Abort,
fewer_names: sess.fewer_names(),
save_temps: sess.opts.cg.save_temps,
+ time_trace: sess.opts.debugging_opts.llvm_time_trace,
opts: Arc::new(sess.opts.clone()),
prof: sess.prof.clone(),
exported_symbols,
// Each LLVM module is automatically sent back to the coordinator for LTO if
// necessary. There's already optimizations in place to avoid sending work
// back to the coordinator if LTO isn't requested.
- return thread::spawn(move || {
+ return B::spawn_thread(cgcx.time_trace, move || {
let mut worker_id_counter = 0;
let mut free_worker_ids = Vec::new();
let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| {
pub struct WorkerFatalError;
fn spawn_work<B: ExtraBackendMethods>(cgcx: CodegenContext<B>, work: WorkItem<B>) {
- let builder = thread::Builder::new().name(work.short_description());
- builder
- .spawn(move || {
- // Set up a destructor which will fire off a message that we're done as
- // we exit.
- struct Bomb<B: ExtraBackendMethods> {
- coordinator_send: Sender<Box<dyn Any + Send>>,
- result: Option<Result<WorkItemResult<B>, FatalError>>,
- worker_id: usize,
- }
- impl<B: ExtraBackendMethods> Drop for Bomb<B> {
- fn drop(&mut self) {
- let worker_id = self.worker_id;
- let msg = match self.result.take() {
- Some(Ok(WorkItemResult::Compiled(m))) => {
- Message::Done::<B> { result: Ok(m), worker_id }
- }
- Some(Ok(WorkItemResult::NeedsLink(m))) => {
- Message::NeedsLink::<B> { module: m, worker_id }
- }
- Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
- Message::NeedsFatLTO::<B> { result: m, worker_id }
- }
- Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => {
- Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id }
- }
- Some(Err(FatalError)) => {
- Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id }
- }
- None => Message::Done::<B> { result: Err(None), worker_id },
- };
- drop(self.coordinator_send.send(Box::new(msg)));
- }
+ B::spawn_named_thread(cgcx.time_trace, work.short_description(), move || {
+ // Set up a destructor which will fire off a message that we're done as
+ // we exit.
+ struct Bomb<B: ExtraBackendMethods> {
+ coordinator_send: Sender<Box<dyn Any + Send>>,
+ result: Option<Result<WorkItemResult<B>, FatalError>>,
+ worker_id: usize,
+ }
+ impl<B: ExtraBackendMethods> Drop for Bomb<B> {
+ fn drop(&mut self) {
+ let worker_id = self.worker_id;
+ let msg = match self.result.take() {
+ Some(Ok(WorkItemResult::Compiled(m))) => {
+ Message::Done::<B> { result: Ok(m), worker_id }
+ }
+ Some(Ok(WorkItemResult::NeedsLink(m))) => {
+ Message::NeedsLink::<B> { module: m, worker_id }
+ }
+ Some(Ok(WorkItemResult::NeedsFatLTO(m))) => {
+ Message::NeedsFatLTO::<B> { result: m, worker_id }
+ }
+ Some(Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer))) => {
+ Message::NeedsThinLTO::<B> { name, thin_buffer, worker_id }
+ }
+ Some(Err(FatalError)) => {
+ Message::Done::<B> { result: Err(Some(WorkerFatalError)), worker_id }
+ }
+ None => Message::Done::<B> { result: Err(None), worker_id },
+ };
+ drop(self.coordinator_send.send(Box::new(msg)));
}
+ }
- let mut bomb = Bomb::<B> {
- coordinator_send: cgcx.coordinator_send.clone(),
- result: None,
- worker_id: cgcx.worker,
- };
+ let mut bomb = Bomb::<B> {
+ coordinator_send: cgcx.coordinator_send.clone(),
+ result: None,
+ worker_id: cgcx.worker,
+ };
- // Execute the work itself, and if it finishes successfully then flag
- // ourselves as a success as well.
- //
- // Note that we ignore any `FatalError` coming out of `execute_work_item`,
- // as a diagnostic was already sent off to the main thread - just
- // surface that there was an error in this worker.
- bomb.result = {
- let _prof_timer = work.start_profiling(&cgcx);
- Some(execute_work_item(&cgcx, work))
- };
- })
- .expect("failed to spawn thread");
+ // Execute the work itself, and if it finishes successfully then flag
+ // ourselves as a success as well.
+ //
+ // Note that we ignore any `FatalError` coming out of `execute_work_item`,
+ // as a diagnostic was already sent off to the main thread - just
+ // surface that there was an error in this worker.
+ bomb.result = {
+ let _prof_timer = work.start_profiling(&cgcx);
+ Some(execute_work_item(&cgcx, work))
+ };
+ })
+ .expect("failed to spawn thread");
}
enum SharedEmitterMessage {
let msg = msg.strip_prefix("error: ").unwrap_or(&msg);
let mut err = match level {
- Level::Error => sess.struct_err(&msg),
+ Level::Error { lint: false } => sess.struct_err(&msg),
Level::Warning => sess.struct_warn(&msg),
Level::Note => sess.struct_note_without_error(&msg),
_ => bug!("Invalid inline asm diagnostic level"),
// info for MSVC debugger. However, wrapping these types' names in a synthetic type
// causes the .natvis engine for WinDbg to fail to display their data, so we opt these
// types out to aid debugging in MSVC.
- let is_slice_or_str = match *inner_type.kind() {
- ty::Slice(_) | ty::Str => true,
- _ => false,
- };
+ let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str);
if !cpp_like_names {
output.push('&');
#![feature(nll)]
#![feature(associated_type_bounds)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
//! This crate contains codegen code that is used by all codegen backends (LLVM and others).
//! The backend-agnostic functions of this crate use functions defined in various traits that
use rustc_hir::LangItem;
use rustc_middle::dep_graph::WorkProduct;
use rustc_middle::middle::dependency_format::Dependencies;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
use rustc_session::cstore::{self, CrateSource};
use rustc_session::utils::NativeLibKind;
crate::target_features::provide(providers);
}
-pub fn provide_extern(providers: &mut Providers) {
+pub fn provide_extern(providers: &mut ExternProviders) {
crate::back::symbol_export::provide_extern(providers);
}
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol};
+use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
use rustc_target::spec::abi::Abi;
self.codegen_argument(&mut bx, location, &mut llargs, last_arg);
}
- let fn_ptr = match (llfn, instance) {
- (Some(llfn), _) => llfn,
- (None, Some(instance)) => bx.get_fn_addr(instance),
+ let (is_indirect_call, fn_ptr) = match (llfn, instance) {
+ (Some(llfn), _) => (true, llfn),
+ (None, Some(instance)) => (false, bx.get_fn_addr(instance)),
_ => span_bug!(span, "no llfn for call"),
};
+ // For backends that support CFI using type membership (i.e., testing whether a given
+ // pointer is associated with a type identifier).
+ if bx.tcx().sess.is_sanitizer_cfi_enabled() && is_indirect_call {
+ // Emit type metadata and checks.
+ // FIXME(rcvalle): Add support for generalized identifiers.
+ // FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
+ let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
+ let typeid_metadata = bx.typeid_metadata(typeid);
+
+ // Test whether the function pointer is associated with the type identifier.
+ let cond = bx.type_test(fn_ptr, typeid_metadata);
+ let mut bx_pass = bx.build_sibling_block("type_test.pass");
+ let mut bx_fail = bx.build_sibling_block("type_test.fail");
+ bx.cond_br(cond, bx_pass.llbb(), bx_fail.llbb());
+
+ helper.do_call(
+ self,
+ &mut bx_pass,
+ fn_abi,
+ fn_ptr,
+ &llargs,
+ destination.as_ref().map(|&(_, target)| (ret_dest, target)),
+ cleanup,
+ );
+
+ bx_fail.abort();
+ bx_fail.unreachable();
+
+ return;
+ }
+
helper.do_call(
self,
&mut bx,
options: ast::InlineAsmOptions,
line_spans: &[Span],
destination: Option<mir::BasicBlock>,
+ instance: Instance<'_>,
) {
let span = terminator.source_info.span;
})
.collect();
- bx.codegen_inline_asm(template, &operands, options, line_spans);
+ bx.codegen_inline_asm(template, &operands, options, line_spans, instance);
if let Some(target) = destination {
helper.funclet_br(self, &mut bx, target);
options,
line_spans,
destination,
+ self.instance,
);
}
}
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
+use rustc_symbol_mangling::typeid_for_fnabi;
use rustc_target::abi::call::{FnAbi, PassMode};
use std::iter;
for (bb, _) in traversal::reverse_postorder(&mir) {
fx.codegen_block(bb);
}
+
+ // For backends that support CFI using type membership (i.e., testing whether a given pointer
+ // is associated with a type identifier).
+ if cx.tcx().sess.is_sanitizer_cfi_enabled() {
+ let typeid = typeid_for_fnabi(cx.tcx(), fn_abi);
+ bx.type_metadata(llfn, typeid);
+ }
}
/// Produces, for each argument, a `Value` pointing at the
let count = self.codegen_operand(&mut bx, count).immediate();
let pointee_layout = dst_val
.layout
- .pointee_info_at(&mut bx, rustc_target::abi::Size::ZERO)
+ .pointee_info_at(&bx, rustc_target::abi::Size::ZERO)
.expect("Expected pointer");
let bytes = bx.mul(count, bx.const_usize(pointee_layout.size.bytes()));
("crypto", Some(sym::arm_target_feature)),
("aes", Some(sym::arm_target_feature)),
("sha2", Some(sym::arm_target_feature)),
+ ("i8mm", Some(sym::arm_target_feature)),
+ ("dotprod", Some(sym::arm_target_feature)),
("v5te", Some(sym::arm_target_feature)),
("v6", Some(sym::arm_target_feature)),
("v6k", Some(sym::arm_target_feature)),
("thumb-mode", Some(sym::arm_target_feature)),
];
-// Commented features are not available in LLVM 10.0, or have since been renamed
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
// FEAT_AdvSimd
("neon", Some(sym::aarch64_target_feature)),
// FEAT_DIT
("dit", Some(sym::aarch64_target_feature)),
// FEAT_FLAGM
- // ("flagm", Some(sym::aarch64_target_feature)),
+ ("flagm", Some(sym::aarch64_target_feature)),
// FEAT_SSBS
("ssbs", Some(sym::aarch64_target_feature)),
// FEAT_SB
("sb", Some(sym::aarch64_target_feature)),
// FEAT_PAUTH
- // ("pauth", Some(sym::aarch64_target_feature)),
+ ("pauth", Some(sym::aarch64_target_feature)),
// FEAT_DPB
("dpb", Some(sym::aarch64_target_feature)),
// FEAT_DPB2
// FEAT_FRINTTS
("frintts", Some(sym::aarch64_target_feature)),
// FEAT_I8MM
- // ("i8mm", Some(sym::aarch64_target_feature)),
+ ("i8mm", Some(sym::aarch64_target_feature)),
// FEAT_F32MM
- // ("f32mm", Some(sym::aarch64_target_feature)),
+ ("f32mm", Some(sym::aarch64_target_feature)),
// FEAT_F64MM
- // ("f64mm", Some(sym::aarch64_target_feature)),
+ ("f64mm", Some(sym::aarch64_target_feature)),
// FEAT_BF16
- // ("bf16", Some(sym::aarch64_target_feature)),
+ ("bf16", Some(sym::aarch64_target_feature)),
// FEAT_RAND
("rand", Some(sym::aarch64_target_feature)),
// FEAT_BTI
("sha3", Some(sym::aarch64_target_feature)),
// FEAT_SM3 & FEAT_SM4
("sm4", Some(sym::aarch64_target_feature)),
+ // FEAT_PAN
+ ("pan", Some(sym::aarch64_target_feature)),
+ // FEAT_LOR
+ ("lor", Some(sym::aarch64_target_feature)),
+ // FEAT_VHE
+ ("vh", Some(sym::aarch64_target_feature)),
+ // FEAT_PMUv3
+ ("pmuv3", Some(sym::aarch64_target_feature)),
+ // FEAT_SPE
+ ("spe", Some(sym::aarch64_target_feature)),
("v8.1a", Some(sym::aarch64_target_feature)),
("v8.2a", Some(sym::aarch64_target_feature)),
("v8.3a", Some(sym::aarch64_target_feature)),
("v8.4a", Some(sym::aarch64_target_feature)),
("v8.5a", Some(sym::aarch64_target_feature)),
- // ("v8.6a", Some(sym::aarch64_target_feature)),
- // ("v8.7a", Some(sym::aarch64_target_feature)),
+ ("v8.6a", Some(sym::aarch64_target_feature)),
+ ("v8.7a", Some(sym::aarch64_target_feature)),
];
const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
operands: &[InlineAsmOperandRef<'tcx, Self>],
options: InlineAsmOptions,
line_spans: &[Span],
+ instance: Instance<'_>,
);
}
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{Ty, TyCtxt};
use rustc_session::{
config::{self, OutputFilenames, PrintRequest},
}
fn provide(&self, _providers: &mut Providers) {}
- fn provide_extern(&self, _providers: &mut Providers) {}
+ fn provide_extern(&self, _providers: &mut ExternProviders) {}
fn codegen_crate<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
) -> TargetMachineFactoryFn<Self>;
fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>;
+
+ fn spawn_thread<F, T>(_time_trace: bool, f: F) -> std::thread::JoinHandle<T>
+ where
+ F: FnOnce() -> T,
+ F: Send + 'static,
+ T: Send + 'static,
+ {
+ std::thread::spawn(f)
+ }
+
+ fn spawn_named_thread<F, T>(
+ _time_trace: bool,
+ name: String,
+ f: F,
+ ) -> std::io::Result<std::thread::JoinHandle<T>>
+ where
+ F: FnOnce() -> T,
+ F: Send + 'static,
+ T: Send + 'static,
+ {
+ std::thread::Builder::new().name(name).spawn(f)
+ }
}
fn range_metadata(&mut self, load: Self::Value, range: WrappingRange);
fn nonnull_metadata(&mut self, load: Self::Value);
+ fn type_metadata(&mut self, function: Self::Function, typeid: String);
+ fn typeid_metadata(&mut self, typeid: String) -> Self::Value;
fn store(&mut self, val: Self::Value, ptr: Self::Value, align: Align) -> Self::Value;
fn store_with_flags(
///
/// Currently has any effect only when LLVM versions prior to 12.0 are used as the backend.
fn sideeffect(&mut self);
+ /// Trait method used to test whether a given pointer is associated with a type identifier.
+ fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value;
/// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
/// Rust defined C-variadic functions.
fn va_start(&mut self, val: Self::Value) -> Self::Value;
impl MachineStopType for ConstEvalErrKind {
fn is_hard_err(&self) -> bool {
- match self {
- Self::Panic { .. } => true,
- _ => false,
- }
+ matches!(self, Self::Panic { .. })
}
}
| DefKind::Static
| DefKind::ConstParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::AssocConst
),
"Unexpected DefKind: {:?}",
// If the function itself is not annotated with `const`, it may still be a `const fn`
// if it resides in a const trait impl.
is_parent_const_impl_raw(tcx, hir_id)
- } else if let hir::Node::Ctor(_) = node {
- true
} else {
- false
+ matches!(node, hir::Node::Ctor(_))
}
}
&mut self,
instance: ty::Instance<'tcx>,
args: &[OpTy<'tcx>],
- is_const_fn: bool,
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
- // The list of functions we handle here must be in sync with
- // `is_lang_special_const_fn` in `transform/check_consts/mod.rs`.
+ // All `#[rustc_do_not_const_check]` functions should be hooked here.
let def_id = instance.def_id();
- if is_const_fn {
- if Some(def_id) == self.tcx.lang_items().const_eval_select() {
- // redirect to const_eval_select_ct
- if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
- return Ok(Some(
- ty::Instance::resolve(
- *self.tcx,
- ty::ParamEnv::reveal_all(),
- const_eval_select,
- instance.substs,
- )
- .unwrap()
- .unwrap(),
- ));
- }
+ if Some(def_id) == self.tcx.lang_items().const_eval_select() {
+ // redirect to const_eval_select_ct
+ if let Some(const_eval_select) = self.tcx.lang_items().const_eval_select_ct() {
+ return Ok(Some(
+ ty::Instance::resolve(
+ *self.tcx,
+ ty::ParamEnv::reveal_all(),
+ const_eval_select,
+ instance.substs,
+ )
+ .unwrap()
+ .unwrap(),
+ ));
}
- return Ok(None);
- }
-
- if Some(def_id) == self.tcx.lang_items().panic_fn()
- || Some(def_id) == self.tcx.lang_items().panic_str()
- || Some(def_id) == self.tcx.lang_items().panic_display()
+ } else if Some(def_id) == self.tcx.lang_items().panic_display()
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
{
// &str or &&str
// Only check non-glue functions
if let ty::InstanceDef::Item(def) = instance.def {
- let mut is_const_fn = true;
-
// Execution might have wandered off into other crates, so we cannot do a stability-
// sensitive check here. But we can at least rule out functions that are not const
// at all.
if !ecx.tcx.is_const_fn_raw(def.did) {
// allow calling functions marked with #[default_method_body_is_const].
if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) {
- is_const_fn = false;
+ // We certainly do *not* want to actually call the fn
+ // though, so be sure we return here.
+ throw_unsup_format!("calling non-const function `{}`", instance)
}
}
- // Some functions we support even if they are non-const -- but avoid testing
- // that for const fn!
- // `const_eval_select` is a const fn because it must use const trait bounds.
- if let Some(new_instance) = ecx.hook_special_const_fn(instance, args, is_const_fn)? {
+ if let Some(new_instance) = ecx.hook_special_const_fn(instance, args)? {
// We call another const fn instead.
return Self::find_mir_or_eval_fn(ecx, new_instance, _abi, args, _ret, _unwind);
}
-
- if !is_const_fn {
- // We certainly do *not* want to actually call the fn
- // though, so be sure we return here.
- throw_unsup_format!("calling non-const function `{}`", instance)
- }
}
// This is a const fn. Call it.
Ok(Some(ecx.load_mir(instance.def, None)?))
args: &[GenericArg<'tcx>],
) -> Result<Self::Path, Self::Error> {
self = print_prefix(self)?;
- let args = args.iter().cloned().filter(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(_) => false,
- _ => true,
- });
+ let args =
+ args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
if args.clone().next().is_some() {
self.generic_delimiters(|cx| cx.comma_sep(args))
} else {
// Figure out how to pass which arguments.
// The Rust ABI is special: ZST get skipped.
- let rust_abi = match caller_abi {
- Abi::Rust | Abi::RustCall => true,
- _ => false,
- };
+ let rust_abi = matches!(caller_abi, Abi::Rust | Abi::RustCall);
+
// We have two iterators: Where the arguments come from,
// and where they go to.
#![feature(trusted_step)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt};
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
-use rustc_mir_dataflow::impls::MaybeMutBorrowedLocals;
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
use super::ops::{self, NonConstOp, Status};
use super::qualifs::{self, CustomEq, HasMutInterior, NeedsDrop, NeedsNonConstDrop};
use super::resolver::FlowSensitiveAnalysis;
-use super::{is_lang_panic_fn, is_lang_special_const_fn, ConstCx, Qualif};
+use super::{ConstCx, Qualif};
use crate::const_eval::is_unstable_const_fn;
-// We are using `MaybeMutBorrowedLocals` as a proxy for whether an item may have been mutated
-// through a pointer prior to the given point. This is okay even though `MaybeMutBorrowedLocals`
-// kills locals upon `StorageDead` because a local will never be used after a `StorageDead`.
-type IndirectlyMutableResults<'mir, 'tcx> =
- rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, MaybeMutBorrowedLocals<'mir, 'tcx>>;
-
type QualifResults<'mir, 'tcx, Q> =
rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
has_mut_interior: Option<QualifResults<'mir, 'tcx, HasMutInterior>>,
needs_drop: Option<QualifResults<'mir, 'tcx, NeedsDrop>>,
needs_non_const_drop: Option<QualifResults<'mir, 'tcx, NeedsNonConstDrop>>,
- indirectly_mutable: Option<IndirectlyMutableResults<'mir, 'tcx>>,
}
impl Qualifs<'mir, 'tcx> {
- pub fn indirectly_mutable(
- &mut self,
- ccx: &'mir ConstCx<'mir, 'tcx>,
- local: Local,
- location: Location,
- ) -> bool {
- let indirectly_mutable = self.indirectly_mutable.get_or_insert_with(|| {
- let ConstCx { tcx, body, param_env, .. } = *ccx;
-
- // We can use `unsound_ignore_borrow_on_drop` here because custom drop impls are not
- // allowed in a const.
- //
- // FIXME(ecstaticmorse): Someday we want to allow custom drop impls. How do we do this
- // without breaking stable code?
- MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env)
- .unsound_ignore_borrow_on_drop()
- .into_engine(tcx, &body)
- .pass_name("const_qualification")
- .iterate_to_fixpoint()
- .into_results_cursor(&body)
- });
-
- indirectly_mutable.seek_before_primary_effect(location);
- indirectly_mutable.get().contains(local)
- }
-
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
///
/// Only updates the cursor if absolutely necessary
});
needs_drop.seek_before_primary_effect(location);
- needs_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+ needs_drop.get().contains(local)
}
/// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`.
});
needs_non_const_drop.seek_before_primary_effect(location);
- needs_non_const_drop.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+ needs_non_const_drop.get().contains(local)
}
/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
});
has_mut_interior.seek_before_primary_effect(location);
- has_mut_interior.get().contains(local) || self.indirectly_mutable(ccx, local, location)
+ has_mut_interior.get().contains(local)
}
fn in_return_place(
.body
.basic_blocks()
.iter_enumerated()
- .find(|(_, block)| match block.terminator().kind {
- TerminatorKind::Return => true,
- _ => false,
- })
+ .find(|(_, block)| matches!(block.terminator().kind, TerminatorKind::Return))
.map(|(bb, _)| bb);
let return_block = match return_block {
.into_results_cursor(&ccx.body);
cursor.seek_after_primary_effect(return_loc);
- cursor.contains(RETURN_PLACE)
+ cursor.get().contains(RETURN_PLACE)
}
};
}
// At this point, we are calling a function, `callee`, whose `DefId` is known...
- if is_lang_special_const_fn(tcx, callee) {
- // `begin_panic` and `panic_display` are generic functions that accept
- // types other than str. Check to enforce that only str can be used in
- // const-eval.
-
- // const-eval of the `begin_panic` fn assumes the argument is `&str`
- if Some(callee) == tcx.lang_items().begin_panic_fn() {
- match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
- ty::Ref(_, ty, _) if ty.is_str() => (),
- _ => self.check_op(ops::PanicNonStr),
- }
- }
- // const-eval of the `panic_display` fn assumes the argument is `&&str`
- if Some(callee) == tcx.lang_items().panic_display() {
- match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
- ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
- {}
- _ => self.check_op(ops::PanicNonStr),
- }
+ // `begin_panic` and `panic_display` are generic functions that accept
+ // types other than str. Check to enforce that only str can be used in
+ // const-eval.
+
+ // const-eval of the `begin_panic` fn assumes the argument is `&str`
+ if Some(callee) == tcx.lang_items().begin_panic_fn() {
+ match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+ ty::Ref(_, ty, _) if ty.is_str() => return,
+ _ => self.check_op(ops::PanicNonStr),
}
+ }
- if is_lang_panic_fn(tcx, callee) {
- // run stability check on non-panic special const fns.
- return;
+ // const-eval of the `panic_display` fn assumes the argument is `&&str`
+ if Some(callee) == tcx.lang_items().panic_display() {
+ match args[0].ty(&self.ccx.body.local_decls, tcx).kind() {
+ ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) =>
+ {
+ return;
+ }
+ _ => self.check_op(ops::PanicNonStr),
}
}
let mut fulfillment_cx = traits::FulfillmentContext::new();
let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span));
fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
- if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(&err, None, false);
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
}
});
}
}
}
-/// Returns `true` if this `DefId` points to one of the official `panic` lang items.
-pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
- Some(def_id) == tcx.lang_items().panic_fn()
- || Some(def_id) == tcx.lang_items().panic_str()
- || Some(def_id) == tcx.lang_items().panic_display()
- || Some(def_id) == tcx.lang_items().begin_panic_fn()
- || Some(def_id) == tcx.lang_items().panic_fmt()
-}
-
-/// Returns `true` if this `DefId` points to one of the lang items that will be handled differently
-/// in const_eval.
-pub fn is_lang_special_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
- // We can allow calls to these functions because `hook_special_const_fn` in
- // `const_eval/machine.rs` ensures the calls are handled specially.
- // Keep in sync with what that function handles!
- is_lang_panic_fn(tcx, def_id) || Some(def_id) == tcx.lang_items().const_eval_select()
-}
-
pub fn rustc_allow_const_fn_unstable(
tcx: TyCtxt<'tcx>,
def_id: DefId,
let mut selcx = SelectionContext::with_constness(&infcx, hir::Constness::Const);
selcx.select(&obligation)
});
- match implsrc {
- Ok(Some(ImplSource::ConstDrop(_)))
- | Ok(Some(ImplSource::Param(_, ty::BoundConstness::ConstIfConst))) => false,
- _ => true,
- }
+ !matches!(
+ implsrc,
+ Ok(Some(
+ ImplSource::ConstDrop(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
+ ))
+ )
}
fn in_adt_inherently(cx: &ConstCx<'_, 'tcx>, adt: &'tcx AdtDef, _: SubstsRef<'tcx>) -> bool {
if Q::in_adt_inherently(cx, def, substs) {
return true;
}
+ if def.is_union() && Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) {
+ return true;
+ }
}
// Otherwise, proceed structurally...
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind};
+use rustc_mir_dataflow::fmt::DebugWithContext;
+use rustc_mir_dataflow::JoinSemiLattice;
+use rustc_span::DUMMY_SP;
+use std::fmt;
use std::marker::PhantomData;
use super::{qualifs, ConstCx, Qualif};
/// A `Visitor` that propagates qualifs between locals. This defines the transfer function of
/// `FlowSensitiveAnalysis`.
///
-/// This transfer does nothing when encountering an indirect assignment. Consumers should rely on
-/// the `MaybeMutBorrowedLocals` dataflow pass to see if a `Local` may have become qualified via
-/// an indirect assignment or function call.
+/// To account for indirect assignments, data flow conservatively assumes that local becomes
+/// qualified immediately after it is borrowed or its address escapes. The borrow must allow for
+/// mutation, which includes shared borrows of places with interior mutability. The type of
+/// borrowed place must contain the qualif.
struct TransferFunction<'a, 'mir, 'tcx, Q> {
ccx: &'a ConstCx<'mir, 'tcx>,
- qualifs_per_local: &'a mut BitSet<Local>,
-
+ state: &'a mut State,
_qualif: PhantomData<Q>,
}
where
Q: Qualif,
{
- fn new(ccx: &'a ConstCx<'mir, 'tcx>, qualifs_per_local: &'a mut BitSet<Local>) -> Self {
- TransferFunction { ccx, qualifs_per_local, _qualif: PhantomData }
+ fn new(ccx: &'a ConstCx<'mir, 'tcx>, state: &'a mut State) -> Self {
+ TransferFunction { ccx, state, _qualif: PhantomData }
}
fn initialize_state(&mut self) {
- self.qualifs_per_local.clear();
+ self.state.qualif.clear();
+ self.state.borrow.clear();
for arg in self.ccx.body.args_iter() {
let arg_ty = self.ccx.body.local_decls[arg].ty;
if Q::in_any_value_of_ty(self.ccx, arg_ty) {
- self.qualifs_per_local.insert(arg);
+ self.state.qualif.insert(arg);
}
}
}
- fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, value: bool) {
+ fn assign_qualif_direct(&mut self, place: &mir::Place<'tcx>, mut value: bool) {
debug_assert!(!place.is_indirect());
+ if !value {
+ for (base, _elem) in place.iter_projections() {
+ let base_ty = base.ty(self.ccx.body, self.ccx.tcx);
+ if base_ty.ty.is_union() && Q::in_any_value_of_ty(self.ccx, base_ty.ty) {
+ value = true;
+ break;
+ }
+ }
+ }
+
match (value, place.as_ref()) {
(true, mir::PlaceRef { local, .. }) => {
- self.qualifs_per_local.insert(local);
+ self.state.qualif.insert(local);
}
// For now, we do not clear the qualif if a local is overwritten in full by
// with aggregates where we overwrite all fields with assignments, which would not
// get this feature.
(false, mir::PlaceRef { local: _, projection: &[] }) => {
- // self.qualifs_per_local.remove(*local);
+ // self.state.qualif.remove(*local);
}
_ => {}
self.assign_qualif_direct(&return_place, qualif);
}
}
+
+ fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
+ // Exact set of permissions granted by AddressOf is undecided. Conservatively assume that
+ // it might allow mutation until resolution of #56604.
+ true
+ }
+
+ fn ref_allows_mutation(&self, kind: mir::BorrowKind, place: mir::Place<'tcx>) -> bool {
+ match kind {
+ mir::BorrowKind::Mut { .. } => true,
+ mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
+ self.shared_borrow_allows_mutation(place)
+ }
+ }
+ }
+
+ /// `&` only allow mutation if the borrowed place is `!Freeze`.
+ ///
+ /// This assumes that it is UB to take the address of a struct field whose type is
+ /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
+ /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
+ /// have to check the type of the borrowed **local** instead of the borrowed **place**
+ /// below. See [rust-lang/unsafe-code-guidelines#134].
+ ///
+ /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
+ fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
+ !place
+ .ty(self.ccx.body, self.ccx.tcx)
+ .ty
+ .is_freeze(self.ccx.tcx.at(DUMMY_SP), self.ccx.param_env)
+ }
}
impl<Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q>
// it no longer needs to be dropped.
if let mir::Operand::Move(place) = operand {
if let Some(local) = place.as_local() {
- self.qualifs_per_local.remove(local);
+ // For backward compatibility with the MaybeMutBorrowedLocals used in an earlier
+ // implementation we retain qualif if a local had been borrowed before. This might
+ // not be strictly necessary since the local is no longer initialized.
+ if !self.state.borrow.contains(local) {
+ self.state.qualif.remove(local);
+ }
}
}
}
rvalue: &mir::Rvalue<'tcx>,
location: Location,
) {
- let qualif = qualifs::in_rvalue::<Q, _>(
- self.ccx,
- &mut |l| self.qualifs_per_local.contains(l),
- rvalue,
- );
+ let qualif =
+ qualifs::in_rvalue::<Q, _>(self.ccx, &mut |l| self.state.qualif.contains(l), rvalue);
if !place.is_indirect() {
self.assign_qualif_direct(place, qualif);
}
self.super_assign(place, rvalue, location);
}
+ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
+ self.super_rvalue(rvalue, location);
+
+ match rvalue {
+ mir::Rvalue::AddressOf(mt, borrowed_place) => {
+ if !borrowed_place.is_indirect()
+ && self.address_of_allows_mutation(*mt, *borrowed_place)
+ {
+ let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
+ if Q::in_any_value_of_ty(self.ccx, place_ty) {
+ self.state.qualif.insert(borrowed_place.local);
+ self.state.borrow.insert(borrowed_place.local);
+ }
+ }
+ }
+
+ mir::Rvalue::Ref(_, kind, borrowed_place) => {
+ if !borrowed_place.is_indirect() && self.ref_allows_mutation(*kind, *borrowed_place)
+ {
+ let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
+ if Q::in_any_value_of_ty(self.ccx, place_ty) {
+ self.state.qualif.insert(borrowed_place.local);
+ self.state.borrow.insert(borrowed_place.local);
+ }
+ }
+ }
+
+ mir::Rvalue::Cast(..)
+ | mir::Rvalue::ShallowInitBox(..)
+ | mir::Rvalue::Use(..)
+ | mir::Rvalue::ThreadLocalRef(..)
+ | mir::Rvalue::Repeat(..)
+ | mir::Rvalue::Len(..)
+ | mir::Rvalue::BinaryOp(..)
+ | mir::Rvalue::CheckedBinaryOp(..)
+ | mir::Rvalue::NullaryOp(..)
+ | mir::Rvalue::UnaryOp(..)
+ | mir::Rvalue::Discriminant(..)
+ | mir::Rvalue::Aggregate(..) => {}
+ }
+ }
+
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
match statement.kind {
StatementKind::StorageDead(local) => {
- self.qualifs_per_local.remove(local);
+ self.state.qualif.remove(local);
+ self.state.borrow.remove(local);
}
_ => self.super_statement(statement, location),
}
if let mir::TerminatorKind::DropAndReplace { value, place, .. } = &terminator.kind {
let qualif = qualifs::in_operand::<Q, _>(
self.ccx,
- &mut |l| self.qualifs_per_local.contains(l),
+ &mut |l| self.state.qualif.contains(l),
value,
);
}
}
+ // We ignore borrow on drop because custom drop impls are not allowed in consts.
+ // FIXME: Reconsider if accounting for borrows in drops is necessary for const drop.
+
// We need to assign qualifs to the dropped location before visiting the operand that
// replaces it since qualifs can be cleared on move.
self.super_terminator(terminator, location);
FlowSensitiveAnalysis { ccx, _qualif: PhantomData }
}
- fn transfer_function(
- &self,
- state: &'a mut BitSet<Local>,
- ) -> TransferFunction<'a, 'mir, 'tcx, Q> {
+ fn transfer_function(&self, state: &'a mut State) -> TransferFunction<'a, 'mir, 'tcx, Q> {
TransferFunction::<Q>::new(self.ccx, state)
}
}
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub(super) struct State {
+ /// Describes whether a local contains qualif.
+ pub qualif: BitSet<Local>,
+ /// Describes whether a local's address escaped and it might become qualified as a result an
+ /// indirect mutation.
+ pub borrow: BitSet<Local>,
+}
+
+impl State {
+ #[inline]
+ pub(super) fn contains(&self, local: Local) -> bool {
+ self.qualif.contains(local)
+ }
+}
+
+impl<C> DebugWithContext<C> for State {
+ fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("qualif: ")?;
+ self.qualif.fmt_with(ctxt, f)?;
+ f.write_str(" borrow: ")?;
+ self.borrow.fmt_with(ctxt, f)?;
+ Ok(())
+ }
+
+ fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ if self == old {
+ return Ok(());
+ }
+
+ if self.qualif != old.qualif {
+ f.write_str("qualif: ")?;
+ self.qualif.fmt_diff_with(&old.qualif, ctxt, f)?;
+ f.write_str("\n")?;
+ }
+
+ if self.borrow != old.borrow {
+ f.write_str("borrow: ")?;
+ self.qualif.fmt_diff_with(&old.borrow, ctxt, f)?;
+ f.write_str("\n")?;
+ }
+
+ Ok(())
+ }
+}
+
+impl JoinSemiLattice for State {
+ fn join(&mut self, other: &Self) -> bool {
+ self.qualif.join(&other.qualif) || self.borrow.join(&other.borrow)
+ }
+}
+
impl<Q> rustc_mir_dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
where
Q: Qualif,
{
- type Domain = BitSet<Local>;
+ type Domain = State;
const NAME: &'static str = Q::ANALYSIS_NAME;
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
- BitSet::new_empty(body.local_decls.len())
+ State {
+ qualif: BitSet::new_empty(body.local_decls.len()),
+ borrow: BitSet::new_empty(body.local_decls.len()),
+ }
}
fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) {
use std::cell::Cell;
use std::{cmp, iter, mem};
-use crate::transform::check_consts::{is_lang_special_const_fn, qualifs, ConstCx};
+use crate::transform::check_consts::{qualifs, ConstCx};
use crate::transform::MirPass;
/// A `MirPass` for promotion.
}
let is_const_fn = match *fn_ty.kind() {
- ty::FnDef(def_id, _) => {
- self.tcx.is_const_fn_raw(def_id) || is_lang_special_const_fn(self.tcx, def_id)
- }
+ ty::FnDef(def_id, _) => self.tcx.is_const_fn_raw(def_id),
_ => false,
};
if !is_const_fn {
new_temp
}
- fn promote_candidate(
- mut self,
- candidate: Candidate,
- next_promoted_id: usize,
- ) -> Option<Body<'tcx>> {
+ fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) -> Body<'tcx> {
let def = self.source.source.with_opt_param();
let mut rvalue = {
let promoted = &mut self.promoted;
let span = self.promoted.span;
self.assign(RETURN_PLACE, rvalue, span);
- Some(self.promoted)
+ self.promoted
}
}
keep_original: false,
};
- //FIXME(oli-obk): having a `maybe_push()` method on `IndexVec` might be nice
- if let Some(mut promoted) = promoter.promote_candidate(candidate, promotions.len()) {
- promoted.source.promoted = Some(promotions.next_index());
- promotions.push(promoted);
- }
+ let mut promoted = promoter.promote_candidate(candidate, promotions.len());
+ promoted.source.promoted = Some(promotions.next_index());
+ promotions.push(promoted);
}
// Insert each of `extra_statements` before its indicated location, which
#![feature(associated_type_bounds)]
#![feature(auto_traits)]
#![feature(bool_to_option)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(control_flow_enum)]
#![feature(core_intrinsics)]
#![feature(extend_one)]
#![feature(thread_id_value)]
#![allow(rustc::default_hash_types)]
#![deny(unaligned_references)]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
+use crate::stable_hasher::{HashStable, StableHasher};
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::iter::FromIterator;
/// stores data in a more compact way. It also supports accessing contiguous
/// ranges of elements as a slice, and slices of already sorted elements can be
/// inserted efficiently.
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, Encodable, Decodable)]
-pub struct SortedMap<K: Ord, V> {
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encodable, Decodable)]
+pub struct SortedMap<K, V> {
data: Vec<(K, V)>,
}
-impl<K: Ord, V> SortedMap<K, V> {
+impl<K, V> Default for SortedMap<K, V> {
+ #[inline]
+ fn default() -> SortedMap<K, V> {
+ SortedMap { data: Vec::new() }
+ }
+}
+
+impl<K, V> SortedMap<K, V> {
#[inline]
- pub fn new() -> SortedMap<K, V> {
- SortedMap { data: vec![] }
+ pub const fn new() -> SortedMap<K, V> {
+ SortedMap { data: Vec::new() }
}
+}
+impl<K: Ord, V> SortedMap<K, V> {
/// Construct a `SortedMap` from a presorted set of elements. This is faster
/// than creating an empty map and then inserting the elements individually.
///
}
}
+impl<K: HashStable<CTX>, V: HashStable<CTX>, CTX> HashStable<CTX> for SortedMap<K, V> {
+ #[inline]
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ self.data.hash_stable(ctx, hasher);
+ }
+}
+
#[cfg(test)]
mod tests;
#[track_caller]
pub fn borrow(&self) -> MappedReadGuard<'_, T> {
let borrow = self.value.borrow();
- if let None = &*borrow {
+ if borrow.is_none() {
panic!("attempted to read from stolen value: {}", std::any::type_name::<T>());
}
ReadGuard::map(borrow, |opt| opt.as_ref().unwrap())
#![feature(nll)]
#![feature(once_cell)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
let builtin = sort_lints(sess, builtin);
let (plugin_groups, builtin_groups): (Vec<_>, _) =
- lint_store.get_lint_groups().partition(|&(.., p)| p);
+ lint_store.get_lint_groups().iter().cloned().partition(|&(.., p)| p);
let plugin_groups = sort_lint_groups(plugin_groups);
let builtin_groups = sort_lint_groups(builtin_groups);
E0783: include_str!("./error_codes/E0783.md"),
E0784: include_str!("./error_codes/E0784.md"),
E0785: include_str!("./error_codes/E0785.md"),
+E0786: include_str!("./error_codes/E0786.md"),
;
// E0006, // merged with E0005
// E0008, // cannot bind by-move into a pattern guard
-// E0019, merged into E0015
-// E0035, merged into E0087/E0089
-// E0036, merged into E0087/E0089
+// E0019, // merged into E0015
+// E0035, // merged into E0087/E0089
+// E0036, // merged into E0087/E0089
// E0068,
// E0085,
// E0086,
// E0134,
// E0135,
// E0141,
-// E0153, unused error code
-// E0157, unused error code
+// E0153, // unused error code
+// E0157, // unused error code
// E0159, // use of trait `{}` as struct constructor
// E0163, // merged into E0071
// E0167,
// between structures with the same definition
// E0385, // {} in an aliasable location
// E0402, // cannot use an outer type parameter in this context
-// E0406, merged into 420
-// E0410, merged into 408
-// E0413, merged into 530
-// E0414, merged into 530
-// E0417, merged into 532
-// E0418, merged into 532
-// E0419, merged into 531
-// E0420, merged into 532
-// E0421, merged into 531
-// E0427, merged into 530
+// E0406, // merged into 420
+// E0410, // merged into 408
+// E0413, // merged into 530
+// E0414, // merged into 530
+// E0417, // merged into 532
+// E0418, // merged into 532
+// E0419, // merged into 531
+// E0420, // merged into 532
+// E0421, // merged into 531
+// E0427, // merged into 530
// E0456, // plugin `..` is not available for triple `..`
E0457, // plugin `..` only found in rlib format, but must be available...
E0460, // found possibly newer version of crate `..`
E0461, // couldn't find crate `..` with expected target triple ..
E0462, // found staticlib `..` instead of rlib or dylib
E0465, // multiple .. candidates for `..` found
-// E0467, removed
-// E0470, removed
+// E0467, // removed
+// E0470, // removed
// E0471, // constant evaluation error (in pattern)
E0472, // llvm_asm! is unsupported on this target
// E0473, // dereference of reference outside its lifetime
E0490, // a value of type `..` is borrowed for too long
E0514, // metadata version mismatch
E0519, // local crate and dependency have same (crate-name, disambiguator)
- // two dependencies have same (crate-name, disambiguator) but different SVH
- E0523,
+ E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
// E0526, // shuffle indices are not constant
// E0540, // multiple rustc_deprecated attributes
// E0548, // replaced with a generic attribute input check
E0711, // a feature has been declared with conflicting stability attributes
E0717, // rustc_promotable without stability attribute
// E0721, // `await` keyword
-// E0723, unstable feature in `const` context
+// E0723, // unstable feature in `const` context
E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
// E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
--- /dev/null
+A metadata file was invalid.
+
+Erroneous code example:
+
+```ignore (needs extern files)
+use ::foo; // error: found invalid metadata files for crate `foo`
+```
+
+When loading crates, each crate must have a valid metadata file.
+Invalid files could be caused by filesystem corruption,
+an IO error while reading the file, or (rarely) a bug in the compiler itself.
+
+Consider deleting the file and recreating it,
+or reporting a bug against the compiler.
/// Maps `Diagnostic::Level` to `snippet::AnnotationType`
fn annotation_type_for_level(level: Level) -> AnnotationType {
match level {
- Level::Bug | Level::Fatal | Level::Error => AnnotationType::Error,
+ Level::Bug | Level::Fatal | Level::Error { .. } => AnnotationType::Error,
Level::Warning => AnnotationType::Warning,
Level::Note => AnnotationType::Note,
Level::Help => AnnotationType::Help,
pub fn is_error(&self) -> bool {
match self.level {
- Level::Bug | Level::Fatal | Level::Error | Level::FailureNote => true,
+ Level::Bug | Level::Fatal | Level::Error { .. } | Level::FailureNote => true,
Level::Warning | Level::Note | Level::Help | Level::Cancelled | Level::Allow => false,
}
MAX_DIGITS
}
+// We replace some characters so the CLI output is always consistent and underlines aligned.
+const OUTPUT_REPLACEMENTS: &[(char, &str)] = &[
+ ('\t', " "), // We do our own tab replacement
+ ('\u{202A}', ""), // The following unicode text flow control characters are inconsistently
+ ('\u{202B}', ""), // supported accross CLIs and can cause confusion due to the bytes on disk
+ ('\u{202D}', ""), // not corresponding to the visible source code, so we replace them always.
+ ('\u{202E}', ""),
+ ('\u{2066}', ""),
+ ('\u{2067}', ""),
+ ('\u{2068}', ""),
+ ('\u{202C}', ""),
+ ('\u{2069}', ""),
+];
+
fn replace_tabs(str: &str) -> String {
- str.replace('\t', " ")
+ let mut s = str.to_string();
+ for (c, replacement) in OUTPUT_REPLACEMENTS {
+ s = s.replace(*c, replacement);
+ }
+ s
}
fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
#![feature(iter_zip)]
#![feature(let_else)]
#![feature(nll)]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
/// as well as inconsistent state observation.
struct HandlerInner {
flags: HandlerFlags,
+ /// The number of lint errors that have been emitted.
+ lint_err_count: usize,
/// The number of errors that have been emitted, including duplicates.
///
/// This is not necessarily the count that's reported to the user once
flags,
inner: Lock::new(HandlerInner {
flags,
+ lint_err_count: 0,
err_count: 0,
warn_count: 0,
deduplicated_err_count: 0,
/// Construct a builder at the `Error` level with the `msg`.
// FIXME: This method should be removed (every error should have an associated error code).
pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
- DiagnosticBuilder::new(self, Level::Error, msg)
+ DiagnosticBuilder::new(self, Level::Error { lint: false }, msg)
+ }
+
+ /// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
+ #[doc(hidden)]
+ pub fn struct_err_lint(&self, msg: &str) -> DiagnosticBuilder<'_> {
+ DiagnosticBuilder::new(self, Level::Error { lint: true }, msg)
}
/// Construct a builder at the `Error` level with the `msg` and the `code`.
}
pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) {
- self.emit_diag_at_span(Diagnostic::new(Error, msg), span);
+ self.emit_diag_at_span(Diagnostic::new(Error { lint: false }, msg), span);
}
pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
- self.emit_diag_at_span(Diagnostic::new_with_code(Error, Some(code), msg), span);
+ self.emit_diag_at_span(
+ Diagnostic::new_with_code(Error { lint: false }, Some(code), msg),
+ span,
+ );
}
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) {
pub fn has_errors(&self) -> bool {
self.inner.borrow().has_errors()
}
+ pub fn has_errors_or_lint_errors(&self) -> bool {
+ self.inner.borrow().has_errors_or_lint_errors()
+ }
pub fn has_errors_or_delayed_span_bugs(&self) -> bool {
self.inner.borrow().has_errors_or_delayed_span_bugs()
}
}
}
if diagnostic.is_error() {
- self.bump_err_count();
+ if matches!(diagnostic.level, Level::Error { lint: true }) {
+ self.bump_lint_err_count();
+ } else {
+ self.bump_err_count();
+ }
} else {
self.bump_warn_count();
}
fn has_errors(&self) -> bool {
self.err_count() > 0
}
+ fn has_errors_or_lint_errors(&self) -> bool {
+ self.has_errors() || self.lint_err_count > 0
+ }
fn has_errors_or_delayed_span_bugs(&self) -> bool {
self.has_errors() || !self.delayed_span_bugs.is_empty()
}
fn has_any_message(&self) -> bool {
- self.err_count() > 0 || self.warn_count > 0
+ self.err_count() > 0 || self.lint_err_count > 0 || self.warn_count > 0
}
fn abort_if_errors(&mut self) {
}
fn err(&mut self, msg: &str) {
- self.emit_error(Error, msg);
+ self.emit_error(Error { lint: false }, msg);
}
/// Emit an error; level should be `Error` or `Fatal`.
}
}
+ fn bump_lint_err_count(&mut self) {
+ self.lint_err_count += 1;
+ self.panic_if_treat_err_as_bug();
+ }
+
fn bump_err_count(&mut self) {
self.err_count += 1;
self.panic_if_treat_err_as_bug();
pub enum Level {
Bug,
Fatal,
- Error,
+ Error {
+ /// If this error comes from a lint, don't abort compilation even when abort_if_errors() is called.
+ lint: bool,
+ },
Warning,
Note,
Help,
fn color(self) -> ColorSpec {
let mut spec = ColorSpec::new();
match self {
- Bug | Fatal | Error => {
+ Bug | Fatal | Error { .. } => {
spec.set_fg(Some(Color::Red)).set_intense(true);
}
Warning => {
pub fn to_str(self) -> &'static str {
match self {
Bug => "error: internal compiler error",
- Fatal | Error => "error",
+ Fatal | Error { .. } => "error",
Warning => "warning",
Note => "note",
Help => "help",
#![feature(proc_macro_span)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
impl ToInternal<rustc_errors::Level> for Level {
fn to_internal(self) -> rustc_errors::Level {
match self {
- Level::Error => rustc_errors::Level::Error,
+ Level::Error => rustc_errors::Level::Error { lint: false },
Level::Warning => rustc_errors::Level::Warning,
Level::Note => rustc_errors::Level::Note,
Level::Help => rustc_errors::Level::Help,
(accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None),
/// Allows panicking during const eval (producing compile-time errors).
(accepted, const_panic, "1.57.0", Some(51999), None),
+ /// Lessens the requirements for structs to implement `Unsize`.
+ (accepted, relaxed_struct_unsize, "1.58.0", Some(81793), None),
// -------------------------------------------------------------------------
// feature-group-end: accepted features
}
}
+// See https://rustc-dev-guide.rust-lang.org/feature-gates.html#feature-gates for more
+// documentation about handling feature gates.
+//
// If you change this, please modify `src/doc/unstable-book` as well.
//
-// Don't ever remove anything from this list; move them to `removed.rs`.
+// Don't ever remove anything from this list; move them to `accepted.rs` if
+// accepted or `removed.rs` if removed.
//
// The version numbers here correspond to the version in which the current status
// was set. This is most important for knowing when a particular feature became
/// Allows `extern "C-cmse-nonsecure-call" fn()`.
(active, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391), None),
- /// Lessens the requirements for structs to implement `Unsize`.
- (active, relaxed_struct_unsize, "1.51.0", Some(81793), None),
-
/// Allows associated types in inherent impls.
(incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
/// not changed from prior instances of the same struct (RFC #2528)
(incomplete, type_changing_struct_update, "1.58.0", Some(86555), None),
+ /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`.
+ (active, doc_auto_cfg, "1.58.0", Some(43781), None),
+
+ /// Allows using `const` operands in inline assembly.
+ (active, asm_const, "1.58.0", Some(72016), None),
+
+ /// Allows using `sym` operands in inline assembly.
+ (active, asm_sym, "1.58.0", Some(72016), None),
+
+ /// Enables experimental inline assembly support for additional architectures.
+ (active, asm_experimental_arch, "1.58.0", Some(72016), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
// Prevents field reads in the marked trait or method to be considered
// during dead code analysis.
rustc_attr!(rustc_trivial_field_reads, Normal, template!(Word), INTERNAL_UNSTABLE),
- // Used by the `rustc::potential_query_instability` lint to warn methods which
- // might not be stable during incremental compilation.
- rustc_attr!(rustc_lint_query_instability, Normal, template!(Word), INTERNAL_UNSTABLE),
// ==========================================================================
// Internal attributes, Const related:
rustc_ast = { path = "../rustc_ast" }
tracing = "0.1"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
-odht = { version = "0.3.0", features = ["nightly"] }
+odht = { version = "0.3.1", features = ["nightly"] }
Use,
/// An `extern` block.
ForeignMod,
- /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`, or `const { 1 + 2}`
+ /// Anonymous constant, e.g. the `1 + 2` in `[u8; 1 + 2]`
AnonConst,
+ /// An inline constant, e.g. `const { 1 + 2 }`
+ InlineConst,
/// Opaque type, aka `impl Trait`.
OpaqueTy,
Field,
DefKind::Use => "import",
DefKind::ForeignMod => "foreign module",
DefKind::AnonConst => "constant expression",
+ DefKind::InlineConst => "inline constant",
DefKind::Field => "field",
DefKind::Impl => "implementation",
DefKind::Closure => "closure",
| DefKind::OpaqueTy
| DefKind::Impl
| DefKind::Use
+ | DefKind::InlineConst
| DefKind::ExternCrate => "an",
DefKind::Macro(macro_kind) => macro_kind.article(),
_ => "a",
// Not namespaced.
DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::ExternCrate
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sorted_map::SortedMap;
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable_Generic;
use rustc_span::source_map::Spanned;
use rustc_target::spec::abi::Abi;
use smallvec::SmallVec;
-use std::collections::BTreeMap;
use std::fmt;
#[derive(Copy, Clone, Encodable, HashStable_Generic)]
/// Attributes owned by a HIR owner.
#[derive(Debug)]
pub struct AttributeMap<'tcx> {
- pub map: BTreeMap<ItemLocalId, &'tcx [Attribute]>,
+ pub map: SortedMap<ItemLocalId, &'tcx [Attribute]>,
pub hash: Fingerprint,
}
impl<'tcx> AttributeMap<'tcx> {
pub const EMPTY: &'static AttributeMap<'static> =
- &AttributeMap { map: BTreeMap::new(), hash: Fingerprint::ZERO };
+ &AttributeMap { map: SortedMap::new(), hash: Fingerprint::ZERO };
#[inline]
pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] {
// used.
pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
/// Content of local bodies.
- pub bodies: IndexVec<ItemLocalId, Option<&'tcx Body<'tcx>>>,
+ pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>,
}
/// Full information resulting from lowering an AST node.
use crate::def_id::{LocalDefId, CRATE_DEF_INDEX};
-use rustc_index::vec::IndexVec;
use std::fmt;
/// Uniquely identifies a node in the HIR of the current crate. It is
owner: LocalDefId { local_def_index: CRATE_DEF_INDEX },
local_id: ItemLocalId::from_u32(0),
};
-
-/// N.B. This collection is currently unused, but will be used by #72015 and future PRs.
-#[derive(Clone, Default, Debug, Encodable, Decodable)]
-pub struct HirIdVec<T> {
- map: IndexVec<LocalDefId, IndexVec<ItemLocalId, T>>,
-}
-
-impl<T> HirIdVec<T> {
- pub fn push_owner(&mut self, id: LocalDefId) {
- self.map.ensure_contains_elem(id, IndexVec::new);
- }
-
- pub fn push(&mut self, id: HirId, value: T) {
- if id.local_id == ItemLocalId::from_u32(0) {
- self.push_owner(id.owner);
- }
- let submap = &mut self.map[id.owner];
- let _ret_id = submap.push(value);
- debug_assert_eq!(_ret_id, id.local_id);
- }
-
- pub fn push_sparse(&mut self, id: HirId, value: T)
- where
- T: Default,
- {
- self.map.ensure_contains_elem(id.owner, IndexVec::new);
- let submap = &mut self.map[id.owner];
- let i = id.local_id.index();
- let len = submap.len();
- if i >= len {
- submap.extend(std::iter::repeat_with(T::default).take(i - len + 1));
- }
- submap[id.local_id] = value;
- }
-
- pub fn get(&self, id: HirId) -> Option<&T> {
- self.map.get(id.owner)?.get(id.local_id)
- }
-
- pub fn get_owner(&self, id: LocalDefId) -> &IndexVec<ItemLocalId, T> {
- &self.map[id]
- }
-
- pub fn iter(&self) -> impl Iterator<Item = &T> {
- self.map.iter().flat_map(|la| la.iter())
- }
-
- pub fn iter_enumerated(&self) -> impl Iterator<Item = (HirId, &T)> {
- self.map.iter_enumerated().flat_map(|(owner, la)| {
- la.iter_enumerated().map(move |(local_id, attr)| (HirId { owner, local_id }, attr))
- })
- }
-}
-
-impl<T> std::ops::Index<HirId> for HirIdVec<T> {
- type Output = T;
-
- fn index(&self, id: HirId) -> &T {
- &self.map[id.owner][id.local_id]
- }
-}
-
-impl<T> std::ops::IndexMut<HirId> for HirIdVec<T> {
- fn index_mut(&mut self, id: HirId) -> &mut T {
- &mut self.map[id.owner][id.local_id]
- }
-}
// in the sense that a crate is not required to have it defined to use it, but a final product
// is required to define it somewhere. Additionally, there are restrictions on crates that use
// a weak lang item, but do not have it defined.
- Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::None;
+ Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::Exact(0);
PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None;
PanicDisplay, sym::panic_display, panic_display, Target::Fn, GenericRequirement::None;
PanicStr, sym::panic_str, panic_str, Target::Fn, GenericRequirement::None;
ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None;
- PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::None;
+ PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::Exact(0);
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
#![feature(let_else)]
#![feature(nll)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_middle;
#[inline]
$v const fn from_usize(value: usize) -> Self {
- #[cfg(not(bootstrap))]
assert!(value <= ($max as usize));
- #[cfg(bootstrap)]
- [()][(value > ($max as usize)) as usize];
unsafe {
Self::from_u32_unchecked(value as u32)
}
#[inline]
$v const fn from_u32(value: u32) -> Self {
- #[cfg(not(bootstrap))]
assert!(value <= $max);
- #[cfg(bootstrap)]
- [()][(value > $max) as usize];
unsafe {
Self::from_u32_unchecked(value)
}
let tcx = self.tcx;
// Select everything, returning errors.
- let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new);
+ let true_errors = fulfill_cx.select_where_possible(self);
debug!("true_errors = {:#?}", true_errors);
if !true_errors.is_empty() {
}
// Anything left unselected *now* must be an ambiguity.
- let ambig_errors = fulfill_cx.select_all_or_error(self).err().unwrap_or_else(Vec::new);
+ let ambig_errors = fulfill_cx.select_all_or_error(self);
debug!("ambig_errors = {:#?}", ambig_errors);
let region_obligations = self.take_registered_region_obligations();
Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
}
+ #[tracing::instrument(level = "debug", skip(self))]
fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
debug_assert_eq!(t, _t);
debug!("ConstInferUnifier: t={:?}", t);
}
}
+ #[tracing::instrument(level = "debug", skip(self))]
fn consts(
&mut self,
c: &'tcx ty::Const<'tcx>,
match c.val {
ty::ConstKind::Infer(InferConst::Var(vid)) => {
- let mut inner = self.infcx.inner.borrow_mut();
- let variable_table = &mut inner.const_unification_table();
-
// Check if the current unification would end up
// unifying `target_vid` with a const which contains
// an inference variable which is unioned with `target_vid`.
//
// Not doing so can easily result in stack overflows.
- if variable_table.unioned(self.target_vid, vid) {
+ if self
+ .infcx
+ .inner
+ .borrow_mut()
+ .const_unification_table()
+ .unioned(self.target_vid, vid)
+ {
return Err(TypeError::CyclicConst(c));
}
- let var_value = variable_table.probe_value(vid);
+ let var_value =
+ self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid);
match var_value.val {
ConstVariableValue::Known { value: u } => self.consts(u, u),
ConstVariableValue::Unknown { universe } => {
if self.for_universe.can_name(universe) {
Ok(c)
} else {
- let new_var_id = variable_table.new_key(ConstVarValue {
- origin: var_value.origin,
- val: ConstVariableValue::Unknown { universe: self.for_universe },
- });
+ let new_var_id =
+ self.infcx.inner.borrow_mut().const_unification_table().new_key(
+ ConstVarValue {
+ origin: var_value.origin,
+ val: ConstVariableValue::Unknown {
+ universe: self.for_universe,
+ },
+ },
+ );
Ok(self.tcx().mk_const_var(new_var_id, c.ty))
}
}
let mut returned_async_output_error = false;
for &sp in values {
if sp.is_desugaring(DesugaringKind::Async) && !returned_async_output_error {
- if &[sp] != err.span.primary_spans() {
+ if [sp] != err.span.primary_spans() {
let mut span: MultiSpan = sp.into();
span.push_span_label(
sp,
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::SubregionOrigin;
-use rustc_errors::{struct_span_err, ErrorReported};
+use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
+use rustc_hir as hir;
+use rustc_hir::{GenericParamKind, Ty};
+use rustc_middle::ty::Region;
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when both the concerned regions are anonymous.
}
};
- let mut e = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
+ let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
- e.span_label(span_1, main_label);
- e.span_label(span_2, String::new());
- e.span_label(span, span_label);
+ err.span_label(span_1, main_label);
+ err.span_label(span_2, String::new());
+ err.span_label(span, span_label);
+
+ self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
if let Some(t) = future_return_type {
let snip = self
(_, "") => None,
_ => Some(s),
})
- .unwrap_or("{unnamed_type}".to_string());
+ .unwrap_or_else(|| "{unnamed_type}".to_string());
- e.span_label(
+ err.span_label(
t.span,
&format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip),
);
}
- e.emit();
+ err.emit();
Some(ErrorReported)
}
+
+ fn suggest_adding_lifetime_params(
+ &self,
+ sub: Region<'tcx>,
+ ty_sup: &Ty<'_>,
+ ty_sub: &Ty<'_>,
+ err: &mut DiagnosticBuilder<'_>,
+ ) {
+ if let (
+ hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
+ hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+ ) = (ty_sub, ty_sup)
+ {
+ if lifetime_sub.name.is_elided() && lifetime_sup.name.is_elided() {
+ if let Some(anon_reg) = self.tcx().is_suitable_region(sub) {
+ let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id);
+ if let hir::Node::Item(&hir::Item {
+ kind: hir::ItemKind::Fn(_, ref generics, ..),
+ ..
+ }) = self.tcx().hir().get(hir_id)
+ {
+ let (suggestion_param_name, introduce_new) = generics
+ .params
+ .iter()
+ .find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+ .and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok())
+ .map(|name| (name, false))
+ .unwrap_or_else(|| ("'a".to_string(), true));
+
+ let mut suggestions = vec![
+ if let hir::LifetimeName::Underscore = lifetime_sub.name {
+ (lifetime_sub.span, suggestion_param_name.clone())
+ } else {
+ (
+ lifetime_sub.span.shrink_to_hi(),
+ suggestion_param_name.clone() + " ",
+ )
+ },
+ if let hir::LifetimeName::Underscore = lifetime_sup.name {
+ (lifetime_sup.span, suggestion_param_name.clone())
+ } else {
+ (
+ lifetime_sup.span.shrink_to_hi(),
+ suggestion_param_name.clone() + " ",
+ )
+ },
+ ];
+
+ if introduce_new {
+ let new_param_suggestion = match &generics.params {
+ [] => (generics.span, format!("<{}>", suggestion_param_name)),
+ [first, ..] => (
+ first.span.shrink_to_lo(),
+ format!("{}, ", suggestion_param_name),
+ ),
+ };
+
+ suggestions.push(new_param_suggestion);
+ }
+
+ err.multipart_suggestion(
+ "consider introducing a named lifetime parameter",
+ suggestions,
+ Applicability::MaybeIncorrect,
+ );
+ err.note(
+ "each elided lifetime in input position becomes a distinct lifetime",
+ );
+ }
+ }
+ }
+ }
+ }
}
self.tainted_by_errors_flag.set(true)
}
- /// Process the region constraints and report any errors that
+ /// Process the region constraints and return any any errors that
/// result. After this, no more unification operations should be
/// done -- or the compiler will panic -- but it is legal to use
/// `resolve_vars_if_possible` as well as `fully_resolve`.
- pub fn resolve_regions_and_report_errors(
+ pub fn resolve_regions(
&self,
region_context: DefId,
outlives_env: &OutlivesEnvironment<'tcx>,
mode: RegionckMode,
- ) {
+ ) -> Vec<RegionResolutionError<'tcx>> {
let (var_infos, data) = {
let mut inner = self.inner.borrow_mut();
let inner = &mut *inner;
let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions));
assert!(old_value.is_none());
+ errors
+ }
+
+ /// Process the region constraints and report any errors that
+ /// result. After this, no more unification operations should be
+ /// done -- or the compiler will panic -- but it is legal to use
+ /// `resolve_vars_if_possible` as well as `fully_resolve`.
+ pub fn resolve_regions_and_report_errors(
+ &self,
+ region_context: DefId,
+ outlives_env: &OutlivesEnvironment<'tcx>,
+ mode: RegionckMode,
+ ) {
+ let errors = self.resolve_regions(region_context, outlives_env, mode);
+
if !self.is_tainted_by_errors() {
// As a heuristic, just skip reporting region errors
// altogether if other errors have been reported while
+use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::infer::{InferCtxt, InferOk};
+use crate::traits;
+use rustc_data_structures::sync::Lrc;
use rustc_data_structures::vec_map::VecMap;
use rustc_hir as hir;
-use rustc_middle::ty::{OpaqueTypeKey, Ty};
+use rustc_hir::def_id::LocalDefId;
+use rustc_middle::ty::fold::BottomUpFolder;
+use rustc_middle::ty::subst::{GenericArgKind, Subst};
+use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitor};
use rustc_span::Span;
+use std::ops::ControlFlow;
+
pub type OpaqueTypeMap<'tcx> = VecMap<OpaqueTypeKey<'tcx>, OpaqueTypeDecl<'tcx>>;
/// Information about the opaque types whose values we
/// The origin of the opaque type.
pub origin: hir::OpaqueTyOrigin,
}
+
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+ /// Replaces all opaque types in `value` with fresh inference variables
+ /// and creates appropriate obligations. For example, given the input:
+ ///
+ /// impl Iterator<Item = impl Debug>
+ ///
+ /// this method would create two type variables, `?0` and `?1`. It would
+ /// return the type `?0` but also the obligations:
+ ///
+ /// ?0: Iterator<Item = ?1>
+ /// ?1: Debug
+ ///
+ /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
+ /// info about the `impl Iterator<..>` type and `?1` to info about
+ /// the `impl Debug` type.
+ ///
+ /// # Parameters
+ ///
+ /// - `parent_def_id` -- the `DefId` of the function in which the opaque type
+ /// is defined
+ /// - `body_id` -- the body-id with which the resulting obligations should
+ /// be associated
+ /// - `param_env` -- the in-scope parameter environment to be used for
+ /// obligations
+ /// - `value` -- the value within which we are instantiating opaque types
+ /// - `value_span` -- the span where the value came from, used in error reporting
+ pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
+ &self,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ value: T,
+ value_span: Span,
+ ) -> InferOk<'tcx, T> {
+ debug!(
+ "instantiate_opaque_types(value={:?}, body_id={:?}, \
+ param_env={:?}, value_span={:?})",
+ value, body_id, param_env, value_span,
+ );
+ let mut instantiator =
+ Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
+ let value = instantiator.instantiate_opaque_types_in_map(value);
+ InferOk { value, obligations: instantiator.obligations }
+ }
+
+ /// Given the map `opaque_types` containing the opaque
+ /// `impl Trait` types whose underlying, hidden types are being
+ /// inferred, this method adds constraints to the regions
+ /// appearing in those underlying hidden types to ensure that they
+ /// at least do not refer to random scopes within the current
+ /// function. These constraints are not (quite) sufficient to
+ /// guarantee that the regions are actually legal values; that
+ /// final condition is imposed after region inference is done.
+ ///
+ /// # The Problem
+ ///
+ /// Let's work through an example to explain how it works. Assume
+ /// the current function is as follows:
+ ///
+ /// ```text
+ /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
+ /// ```
+ ///
+ /// Here, we have two `impl Trait` types whose values are being
+ /// inferred (the `impl Bar<'a>` and the `impl
+ /// Bar<'b>`). Conceptually, this is sugar for a setup where we
+ /// define underlying opaque types (`Foo1`, `Foo2`) and then, in
+ /// the return type of `foo`, we *reference* those definitions:
+ ///
+ /// ```text
+ /// type Foo1<'x> = impl Bar<'x>;
+ /// type Foo2<'x> = impl Bar<'x>;
+ /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
+ /// // ^^^^ ^^
+ /// // | |
+ /// // | substs
+ /// // def_id
+ /// ```
+ ///
+ /// As indicating in the comments above, each of those references
+ /// is (in the compiler) basically a substitution (`substs`)
+ /// applied to the type of a suitable `def_id` (which identifies
+ /// `Foo1` or `Foo2`).
+ ///
+ /// Now, at this point in compilation, what we have done is to
+ /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with
+ /// fresh inference variables C1 and C2. We wish to use the values
+ /// of these variables to infer the underlying types of `Foo1` and
+ /// `Foo2`. That is, this gives rise to higher-order (pattern) unification
+ /// constraints like:
+ ///
+ /// ```text
+ /// for<'a> (Foo1<'a> = C1)
+ /// for<'b> (Foo1<'b> = C2)
+ /// ```
+ ///
+ /// For these equation to be satisfiable, the types `C1` and `C2`
+ /// can only refer to a limited set of regions. For example, `C1`
+ /// can only refer to `'static` and `'a`, and `C2` can only refer
+ /// to `'static` and `'b`. The job of this function is to impose that
+ /// constraint.
+ ///
+ /// Up to this point, C1 and C2 are basically just random type
+ /// inference variables, and hence they may contain arbitrary
+ /// regions. In fact, it is fairly likely that they do! Consider
+ /// this possible definition of `foo`:
+ ///
+ /// ```text
+ /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
+ /// (&*x, &*y)
+ /// }
+ /// ```
+ ///
+ /// Here, the values for the concrete types of the two impl
+ /// traits will include inference variables:
+ ///
+ /// ```text
+ /// &'0 i32
+ /// &'1 i32
+ /// ```
+ ///
+ /// Ordinarily, the subtyping rules would ensure that these are
+ /// sufficiently large. But since `impl Bar<'a>` isn't a specific
+ /// type per se, we don't get such constraints by default. This
+ /// is where this function comes into play. It adds extra
+ /// constraints to ensure that all the regions which appear in the
+ /// inferred type are regions that could validly appear.
+ ///
+ /// This is actually a bit of a tricky constraint in general. We
+ /// want to say that each variable (e.g., `'0`) can only take on
+ /// values that were supplied as arguments to the opaque type
+ /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in
+ /// scope. We don't have a constraint quite of this kind in the current
+ /// region checker.
+ ///
+ /// # The Solution
+ ///
+ /// We generally prefer to make `<=` constraints, since they
+ /// integrate best into the region solver. To do that, we find the
+ /// "minimum" of all the arguments that appear in the substs: that
+ /// is, some region which is less than all the others. In the case
+ /// of `Foo1<'a>`, that would be `'a` (it's the only choice, after
+ /// all). Then we apply that as a least bound to the variables
+ /// (e.g., `'a <= '0`).
+ ///
+ /// In some cases, there is no minimum. Consider this example:
+ ///
+ /// ```text
+ /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
+ /// ```
+ ///
+ /// Here we would report a more complex "in constraint", like `'r
+ /// in ['a, 'b, 'static]` (where `'r` is some region appearing in
+ /// the hidden type).
+ ///
+ /// # Constrain regions, not the hidden concrete type
+ ///
+ /// Note that generating constraints on each region `Rc` is *not*
+ /// the same as generating an outlives constraint on `Tc` iself.
+ /// For example, if we had a function like this:
+ ///
+ /// ```rust
+ /// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> {
+ /// (x, y)
+ /// }
+ ///
+ /// // Equivalent to:
+ /// type FooReturn<'a, T> = impl Foo<'a>;
+ /// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. }
+ /// ```
+ ///
+ /// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0`
+ /// is an inference variable). If we generated a constraint that
+ /// `Tc: 'a`, then this would incorrectly require that `T: 'a` --
+ /// but this is not necessary, because the opaque type we
+ /// create will be allowed to reference `T`. So we only generate a
+ /// constraint that `'0: 'a`.
+ ///
+ /// # The `free_region_relations` parameter
+ ///
+ /// The `free_region_relations` argument is used to find the
+ /// "minimum" of the regions supplied to a given opaque type.
+ /// It must be a relation that can answer whether `'a <= 'b`,
+ /// where `'a` and `'b` are regions that appear in the "substs"
+ /// for the opaque type references (the `<'a>` in `Foo1<'a>`).
+ ///
+ /// Note that we do not impose the constraints based on the
+ /// generic regions from the `Foo1` definition (e.g., `'x`). This
+ /// is because the constraints we are imposing here is basically
+ /// the concern of the one generating the constraining type C1,
+ /// which is the current function. It also means that we can
+ /// take "implied bounds" into account in some cases:
+ ///
+ /// ```text
+ /// trait SomeTrait<'a, 'b> { }
+ /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. }
+ /// ```
+ ///
+ /// Here, the fact that `'b: 'a` is known only because of the
+ /// implied bounds from the `&'a &'b u32` parameter, and is not
+ /// "inherent" to the opaque type definition.
+ ///
+ /// # Parameters
+ ///
+ /// - `opaque_types` -- the map produced by `instantiate_opaque_types`
+ /// - `free_region_relations` -- something that can be used to relate
+ /// the free regions (`'a`) that appear in the impl trait.
+ #[instrument(level = "debug", skip(self))]
+ pub fn constrain_opaque_type(
+ &self,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
+ opaque_defn: &OpaqueTypeDecl<'tcx>,
+ ) {
+ let def_id = opaque_type_key.def_id;
+
+ let tcx = self.tcx;
+
+ let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
+
+ debug!(?concrete_ty);
+
+ let first_own_region = match opaque_defn.origin {
+ hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
+ // We lower
+ //
+ // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
+ //
+ // into
+ //
+ // type foo::<'p0..'pn>::Foo<'q0..'qm>
+ // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
+ //
+ // For these types we only iterate over `'l0..lm` below.
+ tcx.generics_of(def_id).parent_count
+ }
+ // These opaque type inherit all lifetime parameters from their
+ // parent, so we have to check them all.
+ hir::OpaqueTyOrigin::TyAlias => 0,
+ };
+
+ // For a case like `impl Foo<'a, 'b>`, we would generate a constraint
+ // `'r in ['a, 'b, 'static]` for each region `'r` that appears in the
+ // hidden type (i.e., it must be equal to `'a`, `'b`, or `'static`).
+ //
+ // `conflict1` and `conflict2` are the two region bounds that we
+ // detected which were unrelated. They are used for diagnostics.
+
+ // Create the set of choice regions: each region in the hidden
+ // type can be equal to any of the region parameters of the
+ // opaque type definition.
+ let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
+ opaque_type_key.substs[first_own_region..]
+ .iter()
+ .filter_map(|arg| match arg.unpack() {
+ GenericArgKind::Lifetime(r) => Some(r),
+ GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
+ })
+ .chain(std::iter::once(self.tcx.lifetimes.re_static))
+ .collect(),
+ );
+
+ concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
+ tcx: self.tcx,
+ op: |r| {
+ self.member_constraint(
+ opaque_type_key.def_id,
+ opaque_defn.definition_span,
+ concrete_ty,
+ r,
+ &choice_regions,
+ )
+ },
+ });
+ }
+}
+
+// Visitor that requires that (almost) all regions in the type visited outlive
+// `least_region`. We cannot use `push_outlives_components` because regions in
+// closure signatures are not included in their outlives components. We need to
+// ensure all regions outlive the given bound so that we don't end up with,
+// say, `ReVar` appearing in a return type and causing ICEs when other
+// functions end up with region constraints involving regions from other
+// functions.
+//
+// We also cannot use `for_each_free_region` because for closures it includes
+// the regions parameters from the enclosing item.
+//
+// We ignore any type parameters because impl trait values are assumed to
+// capture all the in-scope type parameters.
+struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> {
+ tcx: TyCtxt<'tcx>,
+ op: OP,
+}
+
+impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
+where
+ OP: FnMut(ty::Region<'tcx>),
+{
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
+ fn visit_binder<T: TypeFoldable<'tcx>>(
+ &mut self,
+ t: &ty::Binder<'tcx, T>,
+ ) -> ControlFlow<Self::BreakTy> {
+ t.as_ref().skip_binder().visit_with(self);
+ ControlFlow::CONTINUE
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match *r {
+ // ignore bound regions, keep visiting
+ ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
+ _ => {
+ (self.op)(r);
+ ControlFlow::CONTINUE
+ }
+ }
+ }
+
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ // We're only interested in types involving regions
+ if !ty.flags().intersects(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
+ return ControlFlow::CONTINUE;
+ }
+
+ match ty.kind() {
+ ty::Closure(_, ref substs) => {
+ // Skip lifetime parameters of the enclosing item(s)
+
+ substs.as_closure().tupled_upvars_ty().visit_with(self);
+ substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
+ }
+
+ ty::Generator(_, ref substs, _) => {
+ // Skip lifetime parameters of the enclosing item(s)
+ // Also skip the witness type, because that has no free regions.
+
+ substs.as_generator().tupled_upvars_ty().visit_with(self);
+ substs.as_generator().return_ty().visit_with(self);
+ substs.as_generator().yield_ty().visit_with(self);
+ substs.as_generator().resume_ty().visit_with(self);
+ }
+ _ => {
+ ty.super_visit_with(self);
+ }
+ }
+
+ ControlFlow::CONTINUE
+ }
+}
+
+struct Instantiator<'a, 'tcx> {
+ infcx: &'a InferCtxt<'a, 'tcx>,
+ body_id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ value_span: Span,
+ obligations: Vec<traits::PredicateObligation<'tcx>>,
+}
+
+impl<'a, 'tcx> Instantiator<'a, 'tcx> {
+ fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
+ let tcx = self.infcx.tcx;
+ value.fold_with(&mut BottomUpFolder {
+ tcx,
+ ty_op: |ty| {
+ if ty.references_error() {
+ return tcx.ty_error();
+ } else if let ty::Opaque(def_id, substs) = ty.kind() {
+ // Check that this is `impl Trait` type is
+ // declared by `parent_def_id` -- i.e., one whose
+ // value we are inferring. At present, this is
+ // always true during the first phase of
+ // type-check, but not always true later on during
+ // NLL. Once we support named opaque types more fully,
+ // this same scenario will be able to arise during all phases.
+ //
+ // Here is an example using type alias `impl Trait`
+ // that indicates the distinction we are checking for:
+ //
+ // ```rust
+ // mod a {
+ // pub type Foo = impl Iterator;
+ // pub fn make_foo() -> Foo { .. }
+ // }
+ //
+ // mod b {
+ // fn foo() -> a::Foo { a::make_foo() }
+ // }
+ // ```
+ //
+ // Here, the return type of `foo` references an
+ // `Opaque` indeed, but not one whose value is
+ // presently being inferred. You can get into a
+ // similar situation with closure return types
+ // today:
+ //
+ // ```rust
+ // fn foo() -> impl Iterator { .. }
+ // fn bar() {
+ // let x = || foo(); // returns the Opaque assoc with `foo`
+ // }
+ // ```
+ if let Some(def_id) = def_id.as_local() {
+ let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let parent_def_id = self.infcx.defining_use_anchor;
+ let def_scope_default = || {
+ let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
+ parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
+ };
+ let (in_definition_scope, origin) =
+ match tcx.hir().expect_item(opaque_hir_id).kind {
+ // Anonymous `impl Trait`
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ impl_trait_fn: Some(parent),
+ origin,
+ ..
+ }) => (parent == parent_def_id.to_def_id(), origin),
+ // Named `type Foo = impl Bar;`
+ hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+ impl_trait_fn: None,
+ origin,
+ ..
+ }) => (
+ may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
+ origin,
+ ),
+ _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
+ };
+ if in_definition_scope {
+ let opaque_type_key =
+ OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
+ return self.fold_opaque_ty(ty, opaque_type_key, origin);
+ }
+
+ debug!(
+ "instantiate_opaque_types_in_map: \
+ encountered opaque outside its definition scope \
+ def_id={:?}",
+ def_id,
+ );
+ }
+ }
+
+ ty
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ })
+ }
+
+ #[instrument(skip(self), level = "debug")]
+ fn fold_opaque_ty(
+ &mut self,
+ ty: Ty<'tcx>,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
+ origin: hir::OpaqueTyOrigin,
+ ) -> Ty<'tcx> {
+ let infcx = self.infcx;
+ let tcx = infcx.tcx;
+ let OpaqueTypeKey { def_id, substs } = opaque_type_key;
+
+ // Use the same type variable if the exact same opaque type appears more
+ // than once in the return type (e.g., if it's passed to a type alias).
+ if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
+ debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
+ return opaque_defn.concrete_ty;
+ }
+
+ let ty_var = infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::TypeInference,
+ span: self.value_span,
+ });
+
+ // Ideally, we'd get the span where *this specific `ty` came
+ // from*, but right now we just use the span from the overall
+ // value being folded. In simple cases like `-> impl Foo`,
+ // these are the same span, but not in cases like `-> (impl
+ // Foo, impl Bar)`.
+ let definition_span = self.value_span;
+
+ {
+ let mut infcx = self.infcx.inner.borrow_mut();
+ infcx.opaque_types.insert(
+ OpaqueTypeKey { def_id, substs },
+ OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
+ );
+ infcx.opaque_types_vars.insert(ty_var, ty);
+ }
+
+ debug!("generated new type inference var {:?}", ty_var.kind());
+
+ let item_bounds = tcx.explicit_item_bounds(def_id);
+
+ self.obligations.reserve(item_bounds.len());
+ for (predicate, _) in item_bounds {
+ debug!(?predicate);
+ let predicate = predicate.subst(tcx, substs);
+ debug!(?predicate);
+
+ // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
+ let predicate = predicate.fold_with(&mut BottomUpFolder {
+ tcx,
+ ty_op: |ty| match ty.kind() {
+ ty::Projection(projection_ty) => infcx.infer_projection(
+ self.param_env,
+ *projection_ty,
+ traits::ObligationCause::misc(self.value_span, self.body_id),
+ 0,
+ &mut self.obligations,
+ ),
+ _ => ty,
+ },
+ lt_op: |lt| lt,
+ ct_op: |ct| ct,
+ });
+ debug!(?predicate);
+
+ if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
+ if projection.ty.references_error() {
+ // No point on adding these obligations since there's a type error involved.
+ return tcx.ty_error();
+ }
+ }
+ // Change the predicate to refer to the type variable,
+ // which will be the concrete type instead of the opaque type.
+ // This also instantiates nested instances of `impl Trait`.
+ let predicate = self.instantiate_opaque_types_in_map(predicate);
+
+ let cause =
+ traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
+
+ // Require that the predicate holds for the concrete type.
+ debug!(?predicate);
+ self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
+ }
+
+ ty_var
+ }
+}
+
+/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
+///
+/// Example:
+/// ```rust
+/// pub mod foo {
+/// pub mod bar {
+/// pub trait Bar { .. }
+///
+/// pub type Baz = impl Bar;
+///
+/// fn f1() -> Baz { .. }
+/// }
+///
+/// fn f2() -> bar::Baz { .. }
+/// }
+/// ```
+///
+/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
+/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
+/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
+fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
+ let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+ // Named opaque types can be defined by any siblings or children of siblings.
+ let scope = tcx.hir().get_defining_scope(opaque_hir_id);
+ // We walk up the node tree until we hit the root or the scope of the opaque type.
+ while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
+ hir_id = tcx.hir().get_parent_item(hir_id);
+ }
+ // Syntactically, we are allowed to define the concrete type if:
+ let res = hir_id == scope;
+ trace!(
+ "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}",
+ tcx.hir().find(hir_id),
+ tcx.hir().get(opaque_hir_id),
+ res
+ );
+ res
+}
/// function. We can then add implied bounds and the like from the
/// closure arguments into the environment -- these should only
/// apply in the closure body, so once we exit, we invoke
- /// `pop_snapshot_post_closure` to remove them.
+ /// `pop_snapshot_post_typeck_child` to remove them.
///
/// Example:
///
/// seems like it'd be readily fixed if we wanted. There are
/// similar leaks around givens that seem equally suspicious, to
/// be honest. --nmatsakis
- pub fn push_snapshot_pre_closure(&self) -> usize {
+ pub fn push_snapshot_pre_typeck_child(&self) -> usize {
self.region_bound_pairs_accum.len()
}
- /// See `push_snapshot_pre_closure`.
- pub fn pop_snapshot_post_closure(&mut self, len: usize) {
+ /// See `push_snapshot_pre_typeck_child`.
+ pub fn pop_snapshot_post_typeck_child(&mut self, len: usize) {
self.region_bound_pairs_accum.truncate(len);
}
#![feature(min_specialization)]
#![feature(label_break_value)]
#![recursion_limit = "512"] // For rustdoc
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
obligation: PredicateObligation<'tcx>,
);
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>>;
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;
fn select_all_with_constness_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
_constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
self.select_all_or_error(infcx)
}
- fn select_where_possible(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>>;
+ fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
+ -> Vec<FulfillmentError<'tcx>>;
// FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated
fn select_with_constness_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
_constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
self.select_where_possible(infcx)
}
pub(crate) output_file: Option<PathBuf>,
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
pub(crate) override_queries:
- Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
+ Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
}
impl Compiler {
///
/// The second parameter is local providers and the third parameter is external providers.
pub override_queries:
- Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
+ Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
/// This is a callback from the driver that is called to create a codegen backend.
pub make_codegen_backend:
#![feature(nll)]
#![feature(once_cell)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
mod callbacks;
pub mod interface;
use rustc_metadata::{encode_metadata, EncodedMetadata};
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
use std::io::{self, BufWriter, Write};
use std::lazy::SyncLazy;
use std::marker::PhantomPinned;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use std::pin::Pin;
use std::rc::Rc;
use std::{env, fs, iter};
None
}
-fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool {
+fn output_contains_path(output_paths: &[PathBuf], input_path: &Path) -> bool {
let input_path = input_path.canonicalize().ok();
if input_path.is_none() {
return false;
check_output(output_paths, check)
}
-fn escape_dep_filename(filename: &String) -> String {
+fn escape_dep_filename(filename: &str) -> String {
// Apparently clang and gcc *only* escape spaces:
// https://llvm.org/klaus/clang/commit/9d50634cfc268ecc9a7250226dd5ca0e945240d4
filename.replace(" ", "\\ ")
*providers
});
-pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<Providers> = SyncLazy::new(|| {
- let mut extern_providers = *DEFAULT_QUERY_PROVIDERS;
+pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy<ExternProviders> = SyncLazy::new(|| {
+ let mut extern_providers = ExternProviders::default();
rustc_metadata::provide_extern(&mut extern_providers);
rustc_codegen_ssa::provide_extern(&mut extern_providers);
extern_providers
codegen_backend.provide(&mut local_providers);
let mut extern_providers = *DEFAULT_EXTERN_QUERY_PROVIDERS;
- codegen_backend.provide(&mut extern_providers);
codegen_backend.provide_extern(&mut extern_providers);
if let Some(callback) = compiler.override_queries {
tracked!(new_llvm_pass_manager, Some(true));
tracked!(no_generate_arange_section, true);
tracked!(no_link, true);
+ tracked!(no_unique_section_names, true);
tracked!(no_profiler_runtime, true);
tracked!(osx_rpath_install_name, true);
tracked!(panic_abort_tests, true);
fn visit_item_kind(&mut self, i: &mut ast::ItemKind) {
let is_const = match i {
ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true,
- ast::ItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) => Self::is_sig_const(sig),
+ ast::ItemKind::Fn(box ast::Fn { ref sig, .. }) => Self::is_sig_const(sig),
_ => false,
};
self.run(is_const, |s| noop_visit_item_kind(i, s))
fn flat_map_trait_item(&mut self, i: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
let is_const = match i.kind {
ast::AssocItemKind::Const(..) => true,
- ast::AssocItemKind::Fn(box ast::FnKind(_, ref sig, _, _)) => Self::is_sig_const(sig),
+ ast::AssocItemKind::Fn(box ast::Fn { ref sig, .. }) => Self::is_sig_const(sig),
_ => false,
};
self.run(is_const, |s| noop_flat_map_assoc_item(i, s))
impl EscapeError {
/// Returns true for actual errors, as opposed to warnings.
pub fn is_fatal(&self) -> bool {
- match self {
- EscapeError::UnskippedWhitespaceWarning => false,
- EscapeError::MultipleSkippedLinesWarning => false,
- _ => true,
- }
+ !matches!(
+ self,
+ EscapeError::UnskippedWhitespaceWarning | EscapeError::MultipleSkippedLinesWarning
+ )
}
}
fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
match it.kind {
- ast::ItemKind::Trait(box ast::TraitKind(_, ast::Unsafe::Yes(_), ..)) => self
+ ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self
.report_unsafe(cx, it.span, |lint| {
lint.build("declaration of an `unsafe` trait").emit()
}),
- ast::ItemKind::Impl(box ast::ImplKind { unsafety: ast::Unsafe::Yes(_), .. }) => self
+ ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self
.report_unsafe(cx, it.span, |lint| {
lint.build("implementation of an `unsafe` trait").emit()
}),
// This is a hard error in future editions; avoid linting and erroring
return;
}
- if let ast::AssocItemKind::Fn(box FnKind(_, ref sig, _, _)) = it.kind {
+ if let ast::AssocItemKind::Fn(box Fn { ref sig, .. }) = it.kind {
for arg in sig.decl.inputs.iter() {
if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
if ident.name == kw::Empty {
false
}
- if let rustc_hir::ExprKind::Unary(ref un_op, ref expr_deref) = expr.kind {
- if let rustc_hir::UnOp::Deref = un_op {
- if is_null_ptr(cx, expr_deref) {
- cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
- let mut err = lint.build("dereferencing a null pointer");
- err.span_label(
- expr.span,
- "this code causes undefined behavior when executed",
- );
- err.emit();
- });
- }
+ if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
+ if is_null_ptr(cx, expr_deref) {
+ cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
+ let mut err = lint.build("dereferencing a null pointer");
+ err.span_label(expr.span, "this code causes undefined behavior when executed");
+ err.emit();
+ });
}
}
}
let snippet = template_snippet.as_str();
if let Some(pos) = snippet.find(needle) {
let end = pos
- + &snippet[pos..]
+ + snippet[pos..]
.find(|c| c == ':')
.unwrap_or(snippet[pos..].len() - 1);
let inner = InnerSpan::new(pos, end);
use crate::levels::{is_known_lint_tool, LintLevelsBuilder};
use crate::passes::{EarlyLintPassObject, LateLintPassObject};
+use ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync;
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
use rustc_session::Session;
use rustc_span::lev_distance::find_best_match_for_name;
-use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP};
+use rustc_span::{symbol::Symbol, BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_target::abi;
use tracing::debug;
&self.lints
}
- pub fn get_lint_groups<'t>(
- &'t self,
- ) -> impl Iterator<Item = (&'static str, Vec<LintId>, bool)> + 't {
- // This function is not used in a way which observes the order of lints.
- #[cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
+ pub fn get_lint_groups<'t>(&'t self) -> Vec<(&'static str, Vec<LintId>, bool)> {
self.lint_groups
.iter()
.filter(|(_, LintGroup { depr, .. })| {
.map(|(k, LintGroup { lint_ids, from_plugin, .. })| {
(*k, lint_ids.clone(), *from_plugin)
})
+ .collect()
}
pub fn register_early_pass(
// Now, set up surrounding context.
let sess = self.sess();
match diagnostic {
+ BuiltinLintDiagnostics::UnicodeTextFlow(span, content) => {
+ let spans: Vec<_> = content
+ .char_indices()
+ .filter_map(|(i, c)| {
+ TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
+ let lo = span.lo() + BytePos(2 + i as u32);
+ (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
+ })
+ })
+ .collect();
+ let (an, s) = match spans.len() {
+ 1 => ("an ", ""),
+ _ => ("", "s"),
+ };
+ db.span_label(span, &format!(
+ "this comment contains {}invisible unicode text flow control codepoint{}",
+ an,
+ s,
+ ));
+ for (c, span) in &spans {
+ db.span_label(*span, format!("{:?}", c));
+ }
+ db.note(
+ "these kind of unicode codepoints change the way text flows on \
+ applications that support them, but can cause confusion because they \
+ change the order of characters on the screen",
+ );
+ if !spans.is_empty() {
+ db.multipart_suggestion_with_style(
+ "if their presence wasn't intentional, you can remove them",
+ spans.into_iter().map(|(_, span)| (span, "".to_string())).collect(),
+ Applicability::MachineApplicable,
+ SuggestionStyle::HideCodeAlways,
+ );
+ }
+ },
BuiltinLintDiagnostics::Normal => (),
BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
let (sugg, app) = match sess.source_map().span_to_snippet(span) {
--- /dev/null
+use crate::{EarlyContext, EarlyLintPass, LintContext};
+use ast::util::unicode::{contains_text_flow_control_chars, TEXT_FLOW_CONTROL_CHARS};
+use rustc_ast as ast;
+use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_span::{BytePos, Span, Symbol};
+
+declare_lint! {
+ /// The `text_direction_codepoint_in_literal` lint detects Unicode codepoints that change the
+ /// visual representation of text on screen in a way that does not correspond to their on
+ /// memory representation.
+ ///
+ /// ### Explanation
+ ///
+ /// The unicode characters `\u{202A}`, `\u{202B}`, `\u{202D}`, `\u{202E}`, `\u{2066}`,
+ /// `\u{2067}`, `\u{2068}`, `\u{202C}` and `\u{2069}` make the flow of text on screen change
+ /// its direction on software that supports these codepoints. This makes the text "abc" display
+ /// as "cba" on screen. By leveraging software that supports these, people can write specially
+ /// crafted literals that make the surrounding code seem like it's performing one action, when
+ /// in reality it is performing another. Because of this, we proactively lint against their
+ /// presence to avoid surprises.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(text_direction_codepoint_in_literal)]
+ /// fn main() {
+ /// println!("{:?}", '');
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ pub TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
+ Deny,
+ "detect special Unicode codepoints that affect the visual representation of text on screen, \
+ changing the direction in which text flows",
+}
+
+declare_lint_pass!(HiddenUnicodeCodepoints => [TEXT_DIRECTION_CODEPOINT_IN_LITERAL]);
+
+impl HiddenUnicodeCodepoints {
+ fn lint_text_direction_codepoint(
+ &self,
+ cx: &EarlyContext<'_>,
+ text: Symbol,
+ span: Span,
+ padding: u32,
+ point_at_inner_spans: bool,
+ label: &str,
+ ) {
+ // Obtain the `Span`s for each of the forbidden chars.
+ let spans: Vec<_> = text
+ .as_str()
+ .char_indices()
+ .filter_map(|(i, c)| {
+ TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
+ let lo = span.lo() + BytePos(i as u32 + padding);
+ (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
+ })
+ })
+ .collect();
+
+ cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| {
+ let mut err = lint.build(&format!(
+ "unicode codepoint changing visible direction of text present in {}",
+ label
+ ));
+ let (an, s) = match spans.len() {
+ 1 => ("an ", ""),
+ _ => ("", "s"),
+ };
+ err.span_label(
+ span,
+ &format!(
+ "this {} contains {}invisible unicode text flow control codepoint{}",
+ label, an, s,
+ ),
+ );
+ if point_at_inner_spans {
+ for (c, span) in &spans {
+ err.span_label(*span, format!("{:?}", c));
+ }
+ }
+ err.note(
+ "these kind of unicode codepoints change the way text flows on applications that \
+ support them, but can cause confusion because they change the order of \
+ characters on the screen",
+ );
+ if point_at_inner_spans && !spans.is_empty() {
+ err.multipart_suggestion_with_style(
+ "if their presence wasn't intentional, you can remove them",
+ spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
+ Applicability::MachineApplicable,
+ SuggestionStyle::HideCodeAlways,
+ );
+ err.multipart_suggestion(
+ "if you want to keep them but make them visible in your source code, you can \
+ escape them",
+ spans
+ .into_iter()
+ .map(|(c, span)| {
+ let c = format!("{:?}", c);
+ (span, c[1..c.len() - 1].to_string())
+ })
+ .collect(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
+ // should do the same here to provide the same good suggestions as we do for
+ // literals above.
+ err.note("if their presence wasn't intentional, you can remove them");
+ err.note(&format!(
+ "if you want to keep them but make them visible in your source code, you can \
+ escape them: {}",
+ spans
+ .into_iter()
+ .map(|(c, _)| { format!("{:?}", c) })
+ .collect::<Vec<String>>()
+ .join(", "),
+ ));
+ }
+ err.emit();
+ });
+ }
+}
+impl EarlyLintPass for HiddenUnicodeCodepoints {
+ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
+ if let ast::AttrKind::DocComment(_, comment) = attr.kind {
+ if contains_text_flow_control_chars(&comment.as_str()) {
+ self.lint_text_direction_codepoint(cx, comment, attr.span, 0, false, "doc comment");
+ }
+ }
+ }
+
+ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
+ // byte strings are already handled well enough by `EscapeError::NonAsciiCharInByteString`
+ let (text, span, padding) = match &expr.kind {
+ ast::ExprKind::Lit(ast::Lit { token, kind, span }) => {
+ let text = token.symbol;
+ if !contains_text_flow_control_chars(&text.as_str()) {
+ return;
+ }
+ let padding = match kind {
+ // account for `"` or `'`
+ ast::LitKind::Str(_, ast::StrStyle::Cooked) | ast::LitKind::Char(_) => 1,
+ // account for `r###"`
+ ast::LitKind::Str(_, ast::StrStyle::Raw(val)) => *val as u32 + 2,
+ _ => return,
+ };
+ (text, span, padding)
+ }
+ _ => return,
+ };
+ self.lint_text_direction_codepoint(cx, text, *span, padding, true, "literal");
+ }
+}
use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
-use rustc_hir::*;
+use rustc_hir::{
+ GenericArg, HirId, Item, ItemKind, MutTy, Mutability, Node, Path, PathSegment, QPath, Ty,
+ TyKind,
+};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::hygiene::{ExpnKind, MacroKind};
}
}
-declare_tool_lint! {
- pub rustc::POTENTIAL_QUERY_INSTABILITY,
- Allow,
- "require explicit opt-in when using potentially unstable methods or functions",
- report_in_external_macro: true
-}
-
-declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]);
-
-impl LateLintPass<'_> for QueryStability {
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- // FIXME(rustdoc): This lint uses typecheck results, causing rustdoc to
- // error if there are resolution failures.
- //
- // As internal lints are currently always run if there are `unstable_options`,
- // they are added to the lint store of rustdoc. Internal lints are also
- // not used via the `lint_mod` query. Crate lints run outside of a query
- // so rustdoc currently doesn't disable them.
- //
- // Instead of relying on this, either change crate lints to a query disabled by
- // rustdoc, only run internal lints if the user is explicitly opting in
- // or figure out a different way to avoid running lints for rustdoc.
- if cx.tcx.sess.opts.actually_rustdoc {
- return;
- }
-
- let (def_id, span) = match expr.kind {
- ExprKind::Path(ref path) if let Some(def_id) = cx.qpath_res(path, expr.hir_id).opt_def_id() => {
- (def_id, expr.span)
- }
- ExprKind::MethodCall(_, span, _, _) if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => {
- (def_id, span)
- },
- _ => return,
- };
-
- let substs = cx.typeck_results().node_substs(expr.hir_id);
- if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) {
- let def_id = instance.def_id();
- if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
- cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| {
- let msg = format!(
- "using `{}` can result in unstable query results",
- cx.tcx.item_name(def_id)
- );
- lint.build(&msg)
- .note("if you believe this case to be fine, allow this lint and add a comment explaining your rationale")
- .emit();
- })
- }
- }
- }
-}
-
declare_tool_lint! {
pub rustc::USAGE_OF_TY_TYKIND,
Allow,
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
match &ty.kind {
- TyKind::Path(qpath) => {
- if let QPath::Resolved(_, path) = qpath {
- if let Some(last) = path.segments.iter().last() {
- if lint_ty_kind_usage(cx, last) {
- cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
- lint.build("usage of `ty::TyKind`")
- .help("try using `Ty` instead")
- .emit();
- })
- } else {
- if ty.span.from_expansion() {
- return;
- }
- if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
- if path.segments.len() > 1 {
- cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
- lint.build(&format!("usage of qualified `ty::{}`", t))
- .span_suggestion(
- path.span,
- "try using it unqualified",
- t,
- // The import probably needs to be changed
- Applicability::MaybeIncorrect,
- )
- .emit();
- })
- }
+ TyKind::Path(QPath::Resolved(_, path)) => {
+ if let Some(last) = path.segments.iter().last() {
+ if lint_ty_kind_usage(cx, last) {
+ cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
+ lint.build("usage of `ty::TyKind`")
+ .help("try using `Ty` instead")
+ .emit();
+ })
+ } else {
+ if ty.span.from_expansion() {
+ return;
+ }
+ if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
+ if path.segments.len() > 1 {
+ cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
+ lint.build(&format!("usage of qualified `ty::{}`", t))
+ .span_suggestion(
+ path.span,
+ "try using it unqualified",
+ t,
+ // The import probably needs to be changed
+ Applicability::MaybeIncorrect,
+ )
+ .emit();
+ })
}
}
}
}
fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
- if let TyKind::Path(qpath) = &ty.kind {
- if let QPath::Resolved(_, path) = qpath {
- match path.res {
- Res::Def(_, def_id) => {
- if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id)
- {
- return Some(format!(
- "{}{}",
- name,
- gen_args(path.segments.last().unwrap())
- ));
- }
+ if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
+ match path.res {
+ Res::Def(_, def_id) => {
+ if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id) {
+ return Some(format!("{}{}", name, gen_args(path.segments.last().unwrap())));
}
- // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
- Res::SelfTy(None, Some((did, _))) => {
- if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
- if let Some(name @ (sym::Ty | sym::TyCtxt)) =
- cx.tcx.get_diagnostic_name(adt.did)
- {
- // NOTE: This path is currently unreachable as `Ty<'tcx>` is
- // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
- // is not actually allowed.
- //
- // I(@lcnr) still kept this branch in so we don't miss this
- // if we ever change it in the future.
- return Some(format!("{}<{}>", name, substs[0]));
- }
+ }
+ // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
+ Res::SelfTy(None, Some((did, _))) => {
+ if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
+ if let Some(name @ (sym::Ty | sym::TyCtxt)) =
+ cx.tcx.get_diagnostic_name(adt.did)
+ {
+ // NOTE: This path is currently unreachable as `Ty<'tcx>` is
+ // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
+ // is not actually allowed.
+ //
+ // I(@lcnr) still kept this branch in so we don't miss this
+ // if we ever change it in the future.
+ return Some(format!("{}<{}>", name, substs[0]));
}
}
- _ => (),
}
+ _ => (),
}
}
impl EarlyLintPass for LintPassImpl {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
- if let ast::ItemKind::Impl(box ast::ImplKind { of_trait: Some(lint_pass), .. }) = &item.kind
- {
+ if let ast::ItemKind::Impl(box ast::Impl { of_trait: Some(lint_pass), .. }) = &item.kind {
if let Some(last) = lint_pass.path.segments.last() {
if last.ident.name == sym::LintPass {
let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
#![feature(box_patterns)]
#![feature(crate_visibility_modifier)]
#![feature(format_args_capture)]
-#![feature(if_let_guard)]
#![feature(iter_order_by)]
#![feature(iter_zip)]
#![feature(never_type)]
#![feature(nll)]
#![feature(control_flow_enum)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_middle;
mod context;
mod early;
mod enum_intrinsics_non_enums;
+pub mod hidden_unicode_codepoints;
mod internal;
mod late;
mod levels;
use array_into_iter::ArrayIntoIter;
use builtin::*;
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
+use hidden_unicode_codepoints::*;
use internal::*;
use methods::*;
use non_ascii_idents::*;
DeprecatedAttr: DeprecatedAttr::new(),
WhileTrue: WhileTrue,
NonAsciiIdents: NonAsciiIdents,
+ HiddenUnicodeCodepoints: HiddenUnicodeCodepoints,
IncompleteFeatures: IncompleteFeatures,
RedundantSemicolons: RedundantSemicolons,
UnusedDocComment: UnusedDocComment,
UNUSED_LABELS,
UNUSED_PARENS,
UNUSED_BRACES,
- MUST_NOT_SUSPEND,
REDUNDANT_SEMICOLONS
);
store.register_early_pass(|| Box::new(LintPassImpl));
store.register_lints(&DefaultHashTypes::get_lints());
store.register_late_pass(|| Box::new(DefaultHashTypes));
- store.register_lints(&QueryStability::get_lints());
- store.register_late_pass(|| Box::new(QueryStability));
store.register_lints(&ExistingDocKeyword::get_lints());
store.register_late_pass(|| Box::new(ExistingDocKeyword));
store.register_lints(&TyTyKind::get_lints());
None,
vec![
LintId::of(DEFAULT_HASH_TYPES),
- LintId::of(POTENTIAL_QUERY_INSTABILITY),
LintId::of(USAGE_OF_TY_TYKIND),
LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO),
LintId::of(TY_PASS_BY_REFERENCE),
///
/// ```rust
/// #![feature(must_not_suspend)]
+ /// #![warn(must_not_suspend)]
///
/// #[must_not_suspend]
/// struct SyncThing {}
/// `MutexGuard`'s)
///
pub MUST_NOT_SUSPEND,
- Warn,
+ Allow,
"use of a `#[must_not_suspend]` value across a yield point",
+ @feature_gate = rustc_span::symbol::sym::must_not_suspend;
}
declare_lint! {
BREAK_WITH_LABEL_AND_LOOP,
UNUSED_ATTRIBUTES,
NON_EXHAUSTIVE_OMITTED_PATTERNS,
+ TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
DEREF_INTO_DYN_SUPERTRAIT,
]
}
@feature_gate = sym::non_exhaustive_omitted_patterns_lint;
}
+declare_lint! {
+ /// The `text_direction_codepoint_in_comment` lint detects Unicode codepoints in comments that
+ /// change the visual representation of text on screen in a way that does not correspond to
+ /// their on memory representation.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,compile_fail
+ /// #![deny(text_direction_codepoint_in_comment)]
+ /// fn main() {
+ /// println!("{:?}"); // '');
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Unicode allows changing the visual flow of text on screen in order to support scripts that
+ /// are written right-to-left, but a specially crafted comment can make code that will be
+ /// compiled appear to be part of a comment, depending on the software used to read the code.
+ /// To avoid potential problems or confusion, such as in CVE-2021-42574, by default we deny
+ /// their use.
+ pub TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+ Deny,
+ "invisible directionality-changing codepoints in comment"
+}
+
declare_lint! {
/// The `deref_into_dyn_supertrait` lint is output whenever there is a use of the
/// `Deref` implementation with a `dyn SuperTrait` type as `Output`.
TrailingMacro(bool, Ident),
BreakWithLabelAndLoop(Span),
NamedAsmLabel(String),
+ UnicodeTextFlow(Span, String),
}
/// Lints that are buffered up early on in the `Session` before the
let path = PathBuf::from(s);
println!("cargo:rustc-link-search=native={}", path.parent().unwrap().display());
if target.contains("windows") {
- println!("cargo:rustc-link-lib=static-nobundle={}", stdcppname);
+ println!("cargo:rustc-link-lib=static:-bundle={}", stdcppname);
} else {
println!("cargo:rustc-link-lib=static={}", stdcppname);
}
// Libstdc++ depends on pthread which Rust doesn't link on MinGW
// since nothing else requires it.
if target.contains("windows-gnu") {
- println!("cargo:rustc-link-lib=static-nobundle=pthread");
+ println!("cargo:rustc-link-lib=static:-bundle=pthread");
}
}
/* ProcName */ "rustc");
}
+extern "C" void LLVMTimeTraceProfilerFinishThread() {
+ timeTraceProfilerFinishThread();
+}
+
extern "C" void LLVMTimeTraceProfilerFinish(const char* FileName) {
StringRef FN(FileName);
std::error_code EC;
LLVMRustCodeGenOptLevel RustOptLevel, bool UseSoftFloat,
bool FunctionSections,
bool DataSections,
+ bool UniqueSectionNames,
bool TrapUnreachable,
bool Singlethread,
bool AsmComments,
}
Options.DataSections = DataSections;
Options.FunctionSections = FunctionSections;
+ Options.UniqueSectionNames = UniqueSectionNames;
Options.MCOptions.AsmVerbose = AsmComments;
Options.MCOptions.PreserveAsmComments = AsmComments;
Options.MCOptions.ABIName = ABIStr;
#![feature(nll)]
-#![feature(static_nobundle)]
+#![feature(native_link_modifiers)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
// NOTE: This crate only exists to allow linking on mingw targets.
}
if meta.path().is_ident("project") {
if let Meta::List(list) = meta {
- if let Some(nested) = list.nested.iter().next() {
- if let NestedMeta::Meta(meta) = nested {
- attrs.project = meta.path().get_ident().cloned();
- any_attr = true;
- }
+ if let Some(NestedMeta::Meta(meta)) = list.nested.iter().next() {
+ attrs.project = meta.path().get_ident().cloned();
+ any_attr = true;
}
}
}
/// Always evaluate the query, ignoring its dependencies
EvalAlways(Ident),
+
+ /// Use a separate query provider for local and extern crates
+ SeparateProvideExtern(Ident),
}
impl Parse for QueryModifier {
Ok(QueryModifier::Anon(modifier))
} else if modifier == "eval_always" {
Ok(QueryModifier::EvalAlways(modifier))
+ } else if modifier == "separate_provide_extern" {
+ Ok(QueryModifier::SeparateProvideExtern(modifier))
} else {
Err(Error::new(modifier.span(), "unknown query modifier"))
}
// Always evaluate the query, ignoring its dependencies
eval_always: Option<Ident>,
+
+ /// Use a separate query provider for local and extern crates
+ separate_provide_extern: Option<Ident>,
}
/// Process query modifiers into a struct, erroring on duplicates
let mut no_hash = None;
let mut anon = None;
let mut eval_always = None;
+ let mut separate_provide_extern = None;
for modifier in query.modifiers.0.drain(..) {
match modifier {
QueryModifier::LoadCached(tcx, id, block) => {
}
eval_always = Some(ident);
}
+ QueryModifier::SeparateProvideExtern(ident) => {
+ if separate_provide_extern.is_some() {
+ panic!(
+ "duplicate modifier `separate_provide_extern` for query `{}`",
+ query.name
+ );
+ }
+ separate_provide_extern = Some(ident);
+ }
}
}
let desc = desc.unwrap_or_else(|| {
no_hash,
anon,
eval_always,
+ separate_provide_extern,
}
}
let try_load_from_disk = if let Some((tcx, id, block)) = modifiers.load_cached.as_ref() {
// Use custom code to load the query from disk
quote! {
- #[inline]
- fn try_load_from_disk(
- #tcx: QueryCtxt<'tcx>,
- #id: SerializedDepNodeIndex
- ) -> Option<Self::Value> {
- #block
- }
+ const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>>
+ = Some(|#tcx, #id| { #block });
}
} else {
// Use the default code to load the query from disk
quote! {
- #[inline]
- fn try_load_from_disk(
- tcx: QueryCtxt<'tcx>,
- id: SerializedDepNodeIndex
- ) -> Option<Self::Value> {
- tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id)
- }
+ const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>>
+ = Some(|tcx, id| tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id));
}
};
// expr is a `Block`, meaning that `{ #expr }` gets expanded
// to `{ { stmts... } }`, which triggers the `unused_braces` lint.
quote! {
- #[inline]
#[allow(unused_variables, unused_braces)]
- fn cache_on_disk(
- #tcx: QueryCtxt<'tcx>,
- #key: &Self::Key,
- ) -> bool {
+ #[inline]
+ fn cache_on_disk(#tcx: TyCtxt<'tcx>, #key: &Self::Key) -> bool {
#expr
}
if modifiers.load_cached.is_some() {
panic!("load_cached modifier on query `{}` without a cache modifier", name);
}
- quote! {}
+ quote! {
+ #[inline]
+ fn cache_on_disk(_: TyCtxt<'tcx>, _: &Self::Key) -> bool {
+ false
+ }
+
+ const TRY_LOAD_FROM_DISK: Option<fn(QueryCtxt<$tcx>, SerializedDepNodeIndex) -> Option<Self::Value>> = None;
+ }
};
let (tcx, desc) = modifiers.desc;
let desc = quote! {
#[allow(unused_variables)]
- fn describe(tcx: QueryCtxt<'tcx>, key: Self::Key) -> String {
+ fn describe(tcx: QueryCtxt<$tcx>, key: Self::Key) -> String {
let (#tcx, #key) = (*tcx, key);
::rustc_middle::ty::print::with_no_trimmed_paths(|| format!(#desc).into())
}
};
impls.extend(quote! {
- impl<'tcx> QueryDescription<QueryCtxt<'tcx>> for queries::#name<'tcx> {
+ (#name<$tcx:tt>) => {
#desc
#cache
- }
+ };
});
}
if let Some(eval_always) = &modifiers.eval_always {
attributes.push(quote! { (#eval_always) });
};
+ // Pass on the separate_provide_extern modifier
+ if let Some(separate_provide_extern) = &modifiers.separate_provide_extern {
+ attributes.push(quote! { (#separate_provide_extern) });
+ }
// This uses the span of the query definition for the commas,
// which can be important if we later encounter any ambiguity
}
#[macro_export]
macro_rules! rustc_query_description {
- () => { #query_description_stream }
+ #query_description_stream
}
})
}
[dependencies]
libc = "0.2"
-odht = { version = "0.3.0", features = ["nightly"] }
+odht = { version = "0.3.1", features = ["nightly"] }
snap = "1"
tracing = "0.1"
smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
use proc_macro::bridge::client::ProcMacro;
use std::collections::BTreeMap;
+use std::ops::Fn;
use std::path::Path;
use std::{cmp, env};
use tracing::{debug, info};
#![feature(try_blocks)]
#![feature(never_type)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
extern crate proc_macro;
use std::io::{Read, Result as IoResult, Write};
use std::path::{Path, PathBuf};
use std::{cmp, fmt, fs};
-use tracing::{debug, info, warn};
+use tracing::{debug, info};
#[derive(Clone)]
crate struct CrateLocator<'a> {
self.crate_rejections.via_kind.clear();
self.crate_rejections.via_version.clear();
self.crate_rejections.via_filename.clear();
+ self.crate_rejections.via_invalid.clear();
}
crate fn maybe_load_library_crate(&mut self) -> Result<Option<Library>, CrateError> {
continue;
}
}
- Err(err) => {
- warn!("no metadata found: {}", err);
+ Err(MetadataError::LoadFailure(err)) => {
+ info!("no metadata found: {}", err);
+ // The file was present and created by the same compiler version, but we
+ // couldn't load it for some reason. Give a hard error instead of silently
+ // ignoring it, but only if we would have given an error anyway.
+ self.crate_rejections
+ .via_invalid
+ .push(CrateMismatch { path: lib, got: err });
+ continue;
+ }
+ Err(err @ MetadataError::NotPresent(_)) => {
+ info!("no metadata found: {}", err);
continue;
}
};
fn get_metadata_section(
target: &Target,
flavor: CrateFlavor,
- filename: &Path,
+ filename: &'p Path,
loader: &dyn MetadataLoader,
-) -> Result<MetadataBlob, String> {
+) -> Result<MetadataBlob, MetadataError<'p>> {
if !filename.exists() {
- return Err(format!("no such file: '{}'", filename.display()));
+ return Err(MetadataError::NotPresent(filename));
}
let raw_bytes: MetadataRef = match flavor {
- CrateFlavor::Rlib => loader.get_rlib_metadata(target, filename)?,
+ CrateFlavor::Rlib => {
+ loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)?
+ }
CrateFlavor::Dylib => {
- let buf = loader.get_dylib_metadata(target, filename)?;
+ let buf =
+ loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?;
// The header is uncompressed
let header_len = METADATA_HEADER.len();
debug!("checking {} bytes of metadata-version stamp", header_len);
let header = &buf[..cmp::min(header_len, buf.len())];
if header != METADATA_HEADER {
- return Err(format!(
- "incompatible metadata version found: '{}'",
+ return Err(MetadataError::LoadFailure(format!(
+ "invalid metadata version found: {}",
filename.display()
- ));
+ )));
}
// Header is okay -> inflate the actual metadata
match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) {
Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()),
Err(_) => {
- return Err(format!("failed to decompress metadata: {}", filename.display()));
+ return Err(MetadataError::LoadFailure(format!(
+ "failed to decompress metadata: {}",
+ filename.display()
+ )));
}
}
}
CrateFlavor::Rmeta => {
// mmap the file, because only a small fraction of it is read.
- let file = std::fs::File::open(filename)
- .map_err(|_| format!("failed to open rmeta metadata: '{}'", filename.display()))?;
+ let file = std::fs::File::open(filename).map_err(|_| {
+ MetadataError::LoadFailure(format!(
+ "failed to open rmeta metadata: '{}'",
+ filename.display()
+ ))
+ })?;
let mmap = unsafe { Mmap::map(file) };
- let mmap = mmap
- .map_err(|_| format!("failed to mmap rmeta metadata: '{}'", filename.display()))?;
+ let mmap = mmap.map_err(|_| {
+ MetadataError::LoadFailure(format!(
+ "failed to mmap rmeta metadata: '{}'",
+ filename.display()
+ ))
+ })?;
rustc_erase_owner!(OwningRef::new(mmap).map_owner_box())
}
if blob.is_compatible() {
Ok(blob)
} else {
- Err(format!("incompatible metadata version found: '{}'", filename.display()))
+ Err(MetadataError::LoadFailure(format!(
+ "invalid metadata version found: {}",
+ filename.display()
+ )))
}
}
via_kind: Vec<CrateMismatch>,
via_version: Vec<CrateMismatch>,
via_filename: Vec<CrateMismatch>,
+ via_invalid: Vec<CrateMismatch>,
}
/// Candidate rejection reasons collected during crate search.
NonDylibPlugin(Symbol),
}
+enum MetadataError<'a> {
+ /// The file was missing.
+ NotPresent(&'a Path),
+ /// The file was present and invalid.
+ LoadFailure(String),
+}
+
+impl fmt::Display for MetadataError<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ MetadataError::NotPresent(filename) => {
+ f.write_str(&format!("no such file: '{}'", filename.display()))
+ }
+ MetadataError::LoadFailure(msg) => f.write_str(msg),
+ }
+ }
+}
+
impl CrateError {
crate fn report(self, sess: &Session, span: Span, missing_core: bool) -> ! {
let mut err = match self {
}
err.note(&msg);
err
+ } else if !locator.crate_rejections.via_invalid.is_empty() {
+ let mut err = struct_span_err!(
+ sess,
+ span,
+ E0786,
+ "found invalid metadata files for crate `{}`{}",
+ crate_name,
+ add,
+ );
+ for CrateMismatch { path: _, got } in locator.crate_rejections.via_invalid {
+ err.note(&got);
+ }
+ err
} else {
let mut err = struct_span_err!(
sess,
.libs
.iter()
.filter_map(|lib| lib.name.as_ref())
- .any(|n| &n.as_str() == &lib.name);
+ .any(|n| n.as_str() == lib.name);
if new_name.is_empty() {
self.tcx.sess.err(&format!(
"an empty renaming target was specified for library `{}`",
}
}
- if let EntryKind::Mod(data) = kind {
- for exp in data.decode((self, sess)).reexports.decode((self, sess)) {
+ if let EntryKind::Mod(exports) = kind {
+ for exp in exports.decode((self, sess)) {
match exp.res {
Res::Def(DefKind::Macro(..), _) => {}
_ if macros_only => continue,
}
fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
- if let EntryKind::Mod(m) = self.kind(id) {
- m.decode((self, sess)).expansion
- } else {
- panic!("Expected module, found {:?}", self.local_def_id(id))
+ match self.kind(id) {
+ EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => {
+ self.get_expn_that_defined(id, sess)
+ }
+ _ => panic!("Expected module, found {:?}", self.local_def_id(id)),
}
}
use rustc_middle::hir::exports::Export;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::middle::stability::DeprecationEntry;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt, Visibility};
use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule};
use rustc_session::utils::NativeLibKind;
macro_rules! provide {
(<$lt:tt> $tcx:ident, $def_id:ident, $other:ident, $cdata:ident,
$($name:ident => $compute:block)*) => {
- pub fn provide_extern(providers: &mut Providers) {
+ pub fn provide_extern(providers: &mut ExternProviders) {
$(fn $name<$lt>(
$tcx: TyCtxt<$lt>,
def_id_arg: ty::query::query_keys::$name<$lt>,
$compute
})*
- *providers = Providers {
+ *providers = ExternProviders {
$($name,)*
..*providers
};
| DefKind::ConstParam
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
DefKind::Use
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
(true, mir_opt_base)
}
// Constants
- DefKind::AnonConst | DefKind::AssocConst | DefKind::Static | DefKind::Const => {
- (true, false)
- }
+ DefKind::AnonConst
+ | DefKind::InlineConst
+ | DefKind::AssocConst
+ | DefKind::Static
+ | DefKind::Const => (true, false),
// Full-fledged functions
DefKind::AssocFn | DefKind::Fn => {
let generics = tcx.generics_of(def_id);
| DefKind::Use
| DefKind::LifetimeParam
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::GlobalAsm
| DefKind::Closure
| DefKind::Generator
| DefKind::AssocFn
| DefKind::AssocConst
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Impl
| DefKind::Field
Lazy::empty()
};
- let data = ModData { reexports, expansion: tcx.expn_that_defined(local_def_id) };
-
- record!(self.tables.kind[def_id] <- EntryKind::Mod(self.lazy(data)));
+ record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
if self.is_proc_macro {
record!(self.tables.children[def_id] <- &[]);
+ // Encode this here because we don't do it in encode_def_ids.
+ record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
} else {
record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| {
item_id.def_id.local_def_index
Union(Lazy<VariantData>, ReprOptions),
Fn(Lazy<FnData>),
ForeignFn(Lazy<FnData>),
- Mod(Lazy<ModData>),
+ Mod(Lazy<[Export]>),
MacroDef(Lazy<MacroDef>),
ProcMacro(MacroKind),
Closure,
#[derive(Encodable, Decodable)]
struct RenderedConst(String);
-#[derive(MetadataEncodable, MetadataDecodable)]
-struct ModData {
- reexports: Lazy<[Export]>,
- expansion: ExpnId,
-}
-
#[derive(MetadataEncodable, MetadataDecodable)]
struct FnData {
asyncness: hir::IsAsync,
};
DefKind::Ctor(ctor_of, def::CtorKind::from_hir(variant_data))
}
- Node::AnonConst(_) => DefKind::AnonConst,
+ Node::AnonConst(_) => {
+ let inline = match self.find(self.get_parent_node(hir_id)) {
+ Some(Node::Expr(&Expr {
+ kind: ExprKind::ConstBlock(ref anon_const), ..
+ })) if anon_const.hir_id == hir_id => true,
+ _ => false,
+ };
+ if inline { DefKind::InlineConst } else { DefKind::AnonConst }
+ }
Node::Field(_) => DefKind::Field,
Node::Expr(expr) => match expr.kind {
ExprKind::Closure(.., None) => DefKind::Closure,
}
pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
- self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[id.hir_id.local_id].unwrap()
+ self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id]
}
pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
.iter_enumerated()
.flat_map(move |(owner, owner_info)| {
let bodies = &owner_info.as_ref()?.nodes.bodies;
- Some(bodies.iter_enumerated().filter_map(move |(local_id, body)| {
- if body.is_none() {
- return None;
- }
+ Some(bodies.iter().map(move |&(local_id, _)| {
let hir_id = HirId { owner, local_id };
let body_id = BodyId { hir_id };
- Some(self.body_owner_def_id(body_id))
+ self.body_owner_def_id(body_id)
}))
})
.flatten()
par_iter(&self.krate().owners.raw).enumerate().for_each(|(owner, owner_info)| {
let owner = LocalDefId::new(owner);
if let Some(owner_info) = owner_info {
- par_iter(&owner_info.nodes.bodies.raw).enumerate().for_each(|(local_id, body)| {
- if body.is_some() {
- let local_id = ItemLocalId::new(local_id);
- let hir_id = HirId { owner, local_id };
- let body_id = BodyId { hir_id };
- f(self.body_owner_def_id(body_id))
- }
+ par_iter(owner_info.nodes.bodies.range(..)).for_each(|(local_id, _)| {
+ let hir_id = HirId { owner, local_id: *local_id };
+ let body_id = BodyId { hir_id };
+ f(self.body_owner_def_id(body_id))
})
}
});
let krate = self.krate();
for (owner, info) in krate.owners.iter_enumerated() {
if let Some(info) = info {
- for (&local_id, attrs) in info.attrs.map.iter() {
- let id = HirId { owner, local_id };
+ for (local_id, attrs) in info.attrs.map.iter() {
+ let id = HirId { owner, local_id: *local_id };
for a in *attrs {
visitor.visit_attribute(id, a)
}
#![feature(try_reserve_kind)]
#![feature(nonzero_ops)]
#![recursion_limit = "512"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate bitflags;
(Level::Warn, None) => sess.struct_warn(""),
(Level::ForceWarn, Some(span)) => sess.struct_span_force_warn(span, ""),
(Level::ForceWarn, None) => sess.struct_force_warn(""),
- (Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
- (Level::Deny | Level::Forbid, None) => sess.struct_err(""),
+ (Level::Deny | Level::Forbid, Some(span)) => {
+ let mut builder = sess.diagnostic().struct_err_lint("");
+ builder.set_span(span);
+ builder
+ }
+ (Level::Deny | Level::Forbid, None) => sess.diagnostic().struct_err_lint(""),
};
// If this code originates in a foreign macro, aka something that this crate
/// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors,
/// so this method lets us detect them and `bug!` on unexpected errors.
pub fn formatted_string(&self) -> bool {
- match self {
+ matches!(
+ self,
InterpError::Unsupported(UnsupportedOpInfo::Unsupported(_))
- | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
- | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_)) => true,
- _ => false,
- }
+ | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::ValidationFailure { .. })
+ | InterpError::UndefinedBehavior(UndefinedBehaviorInfo::Ub(_))
+ )
}
/// Should this error be reported as a hard error, preventing compilation, or a soft error,
mut self,
mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection,
) -> Self {
- self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect();
+ self.contents = self.contents.into_iter().map(|(proj, span)| (f(proj), span)).collect();
self
}
write!(w, "static {}", if tcx.is_mutable_static(def_id) { "mut " } else { "" })?
}
(_, _) if is_function => write!(w, "fn ")?,
- (DefKind::AnonConst, _) => {} // things like anon const, not an item
+ (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item
_ => bug!("Unexpected def kind {:?}", kind),
}
for statement in statements {
let source_range = source_range_no_file(tcx, &statement.source_info.span);
text.push(format!(
- "\n{}{}: {}: {}",
+ "\n{}{}: {}: {:?}",
TOOLTIP_INDENT,
source_range,
statement_kind_name(&statement),
- format!("{:?}", statement)
+ statement
));
}
if let Some(term) = terminator {
/// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
query const_param_default(param: DefId) -> &'tcx ty::Const<'tcx> {
desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) }
+ separate_provide_extern
}
query default_anon_const_substs(key: DefId) -> SubstsRef<'tcx> {
path = tcx.def_path_str(key),
}
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query analysis(key: ()) -> Result<(), ErrorReported> {
desc { |tcx| "computing generics of `{}`", tcx.def_path_str(key) }
storage(ArenaCacheSelector<'tcx>)
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
/// Maps from the `DefId` of an item (trait/struct/enum/fn) to the
/// Bounds from the parent (e.g. with nested impl trait) are not included.
query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Elaborated version of the predicates from `explicit_item_bounds`.
query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
desc { "looking up the native libraries of a linked crate" }
+ separate_provide_extern
}
query lint_levels(_: ()) -> LintLevelMap {
// This query reads from untracked data in definitions.
eval_always
desc { |tcx| "expansion that defined `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query is_panic_runtime(_: CrateNum) -> bool {
fatal_cycle
desc { "checking if the crate is_panic_runtime" }
+ separate_provide_extern
}
/// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
query mir_const_qualif(key: DefId) -> mir::ConstQualifs {
desc { |tcx| "const checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query mir_const_qualif_const_arg(
key: (LocalDefId, DefId)
desc {
|tcx| "building an abstract representation for {}", tcx.def_path_str(key),
}
+ separate_provide_extern
}
/// Try to build an abstract representation of the given constant.
query thir_abstract_const_of_const_arg(
) -> &'tcx mir::Body<'tcx> {
desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
query optimized_mir(key: DefId) -> &'tcx mir::Body<'tcx> {
desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
/// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
query promoted_mir(key: DefId) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
desc { |tcx| "optimizing promoted MIR for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
+ separate_provide_extern
}
query promoted_mir_of_const_arg(
key: (LocalDefId, DefId)
/// Returns the predicates written explicitly by the user.
query explicit_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing explicit predicates of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Returns the inferred outlives predicates (e.g., for `struct
/// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`).
query inferred_outlives_of(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
desc { |tcx| "computing inferred outlives predicates of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Maps from the `DefId` of a trait to the list of
/// additional acyclicity requirements).
query super_predicates_of(key: DefId) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing the super predicates of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// The `Option<Ident>` is the name of an associated type. If it is `None`, then this query
query trait_def(key: DefId) -> ty::TraitDef {
desc { |tcx| "computing trait definition for `{}`", tcx.def_path_str(key) }
storage(ArenaCacheSelector<'tcx>)
+ separate_provide_extern
}
query adt_def(key: DefId) -> &'tcx ty::AdtDef {
desc { |tcx| "computing ADT definition for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query adt_destructor(key: DefId) -> Option<ty::Destructor> {
desc { |tcx| "computing `Drop` impl for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
// The cycle error here should be reported as an error by `check_representable`.
/// `is_const_fn` function.
query is_const_fn_raw(key: DefId) -> bool {
desc { |tcx| "checking if item is const fn: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query asyncness(key: DefId) -> hir::IsAsync {
desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Returns `true` if calls to the function may be promoted.
/// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
query is_foreign_item(key: DefId) -> bool {
desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Returns `Some(mutability)` if the node pointed to by `def_id` is a static item.
query static_mutability(def_id: DefId) -> Option<hir::Mutability> {
desc { |tcx| "looking up static mutability of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator.
query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> {
desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Gets a map with the variance of every item; use `item_variance` instead.
/// Maps from the `DefId` of a type or region parameter to its (inferred) variance.
query variances_of(def_id: DefId) -> &'tcx [ty::Variance] {
desc { |tcx| "computing the variances of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Maps from thee `DefId` of a type to its (inferred) outlives.
/// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items.
query associated_item_def_ids(key: DefId) -> &'tcx [DefId] {
desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
/// Maps from a trait item to the trait item "descriptor".
query associated_item(key: DefId) -> ty::AssocItem {
desc { |tcx| "computing associated item data for `{}`", tcx.def_path_str(key) }
storage(ArenaCacheSelector<'tcx>)
+ separate_provide_extern
}
/// Collects the associated items defined on a trait or impl.
/// Return `None` if this is an inherent impl.
query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
desc { |tcx| "computing trait implemented by `{}`", tcx.def_path_str(impl_id) }
+ separate_provide_extern
}
query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
+ separate_provide_extern
}
query issue33140_self_ty(key: DefId) -> Option<ty::Ty<'tcx>> {
query inherent_impls(key: DefId) -> &'tcx [DefId] {
desc { |tcx| "collecting inherent impls for `{}`", tcx.def_path_str(key) }
eval_always
+ separate_provide_extern
}
/// The result of unsafety-checking this `LocalDefId`.
desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
}
- /// The signature of functions.
+ /// Computes the signature of the function.
query fn_sig(key: DefId) -> ty::PolyFnSig<'tcx> {
desc { |tcx| "computing function signature of `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
+ /// Performs lint checking for the module.
query lint_mod(key: LocalDefId) -> () {
desc { |tcx| "linting {}", describe_as_module(key, tcx) }
}
desc { |tcx| "checking attributes in {}", describe_as_module(key, tcx) }
}
+ /// Checks for uses of unstable APIs in the module.
query check_mod_unstable_api_usage(key: LocalDefId) -> () {
desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) }
}
}
/// Caches `CoerceUnsized` kinds for impls on custom types.
- query coerce_unsized_info(key: DefId)
- -> ty::adjustment::CoerceUnsizedInfo {
- desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
- }
+ query coerce_unsized_info(key: DefId) -> ty::adjustment::CoerceUnsizedInfo {
+ desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
+ }
query typeck_item_bodies(_: ()) -> () {
desc { "type-checking all item bodies" }
/// additional requirements that the closure's creator must verify.
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if(tcx) { tcx.is_closure(key.to_def_id()) }
+ cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
}
query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
desc {
desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) }
}
+ /// Generates a MIR body for the shim.
query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
storage(ArenaCacheSelector<'tcx>)
desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) }
query opt_def_kind(def_id: DefId) -> Option<DefKind> {
desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
+ /// Gets the span for the definition.
query def_span(def_id: DefId) -> Span {
desc { |tcx| "looking up span for `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
+ /// Gets the span for the identifier of the definition.
query def_ident_span(def_id: DefId) -> Option<Span> {
desc { |tcx| "looking up span for `{}`'s identifier", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query lookup_stability(def_id: DefId) -> Option<&'tcx attr::Stability> {
desc { |tcx| "looking up stability of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query lookup_const_stability(def_id: DefId) -> Option<&'tcx attr::ConstStability> {
desc { |tcx| "looking up const stability of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query should_inherit_track_caller(def_id: DefId) -> bool {
query lookup_deprecation_entry(def_id: DefId) -> Option<DeprecationEntry> {
desc { |tcx| "checking whether `{}` is deprecated", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query item_attrs(def_id: DefId) -> &'tcx [ast::Attribute] {
desc { |tcx| "collecting attributes of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query codegen_fn_attrs(def_id: DefId) -> CodegenFnAttrs {
query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Gets the rendered value of the specified constant or associated constant.
/// Used by rustdoc.
query rendered_const(def_id: DefId) -> String {
desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query impl_parent(def_id: DefId) -> Option<DefId> {
desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Given an `associated_item`, find the trait it belongs to.
/// Return `None` if the `DefId` is not an associated item.
query trait_of_item(associated_item: DefId) -> Option<DefId> {
desc { |tcx| "finding trait defining `{}`", tcx.def_path_str(associated_item) }
+ separate_provide_extern
}
query is_ctfe_mir_available(key: DefId) -> bool {
desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query is_mir_available(key: DefId) -> bool {
desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
+ separate_provide_extern
}
query own_existential_vtable_entries(
query dylib_dependency_formats(_: CrateNum)
-> &'tcx [(CrateNum, LinkagePreference)] {
desc { "dylib dependency formats of crate" }
+ separate_provide_extern
}
query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
query is_compiler_builtins(_: CrateNum) -> bool {
fatal_cycle
desc { "checking if the crate is_compiler_builtins" }
+ separate_provide_extern
}
query has_global_allocator(_: CrateNum) -> bool {
// This query depends on untracked global state in CStore
eval_always
fatal_cycle
desc { "checking if the crate has_global_allocator" }
+ separate_provide_extern
}
query has_panic_handler(_: CrateNum) -> bool {
fatal_cycle
desc { "checking if the crate has_panic_handler" }
+ separate_provide_extern
}
query is_profiler_runtime(_: CrateNum) -> bool {
fatal_cycle
desc { "query a crate is `#![profiler_runtime]`" }
+ separate_provide_extern
}
query panic_strategy(_: CrateNum) -> PanicStrategy {
fatal_cycle
desc { "query a crate's configured panic strategy" }
+ separate_provide_extern
}
query panic_in_drop_strategy(_: CrateNum) -> PanicStrategy {
fatal_cycle
desc { "query a crate's configured panic-in-drop strategy" }
+ separate_provide_extern
}
query is_no_builtins(_: CrateNum) -> bool {
fatal_cycle
desc { "test whether a crate has `#![no_builtins]`" }
+ separate_provide_extern
}
query symbol_mangling_version(_: CrateNum) -> SymbolManglingVersion {
fatal_cycle
desc { "query a crate's symbol mangling version" }
+ separate_provide_extern
}
query extern_crate(def_id: DefId) -> Option<&'tcx ExternCrate> {
eval_always
desc { "getting crate's ExternCrateData" }
+ separate_provide_extern
}
query specializes(_: (DefId, DefId)) -> bool {
query impl_defaultness(def_id: DefId) -> hir::Defaultness {
desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query impl_constness(def_id: DefId) -> hir::Constness {
desc { |tcx| "looking up whether `{}` is a const impl", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query check_item_well_formed(key: LocalDefId) -> () {
-> DefIdMap<SymbolExportLevel> {
storage(ArenaCacheSelector<'tcx>)
desc { "looking up the exported symbols of a crate" }
+ separate_provide_extern
}
query is_reachable_non_generic(def_id: DefId) -> bool {
desc { |tcx| "checking whether `{}` is an exported symbol", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query is_unreachable_local_definition(def_id: LocalDefId) -> bool {
desc { |tcx|
"collecting available upstream monomorphizations for `{}`",
tcx.def_path_str(def_id),
}
+ separate_provide_extern
}
/// Returns the upstream crate that exports drop-glue for the given
query foreign_modules(_: CrateNum) -> Lrc<FxHashMap<DefId, ForeignModule>> {
desc { "looking up the foreign modules of a linked crate" }
+ separate_provide_extern
}
/// Identifies the entry-point (e.g., the `main` function) for a given
query crate_hash(_: CrateNum) -> Svh {
eval_always
desc { "looking up the hash a crate" }
+ separate_provide_extern
}
query crate_host_hash(_: CrateNum) -> Option<Svh> {
eval_always
desc { "looking up the hash of a host version of a crate" }
+ separate_provide_extern
}
query extra_filename(_: CrateNum) -> String {
eval_always
desc { "looking up the extra filename for a crate" }
+ separate_provide_extern
}
query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
eval_always
desc { "looking up the paths for extern crates" }
+ separate_provide_extern
}
/// Given a crate and a trait, look up all impls of that trait in the crate.
query implementations_of_trait(_: (CrateNum, DefId))
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
desc { "looking up implementations of a trait in a crate" }
+ separate_provide_extern
}
/// Given a crate, look up all trait impls in that crate.
query all_trait_implementations(_: CrateNum)
-> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
desc { "looking up all (?) trait implementations" }
+ separate_provide_extern
}
query is_dllimport_foreign_item(def_id: DefId) -> bool {
query visibility(def_id: DefId) -> ty::Visibility {
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
/// Computes the set of modules from which this type is visibly uninhabited.
query dep_kind(_: CrateNum) -> CrateDepKind {
eval_always
desc { "fetching what a dependency looks like" }
+ separate_provide_extern
}
+
+ /// Gets the name of the crate.
query crate_name(_: CrateNum) -> Symbol {
eval_always
desc { "fetching what a crate is named" }
+ separate_provide_extern
}
query item_children(def_id: DefId) -> &'tcx [Export] {
desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) }
+ separate_provide_extern
}
query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
query defined_lib_features(_: CrateNum)
-> &'tcx [(Symbol, Option<Symbol>)] {
desc { "calculating the lib features defined in a crate" }
+ separate_provide_extern
}
/// Returns the lang items defined in another crate by loading it from metadata.
query get_lang_items(_: ()) -> LanguageItems {
/// Returns the lang items defined in another crate by loading it from metadata.
query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] {
desc { "calculating the lang items defined in a crate" }
+ separate_provide_extern
}
/// Returns the diagnostic items defined in a crate.
query diagnostic_items(_: CrateNum) -> rustc_hir::diagnostic_items::DiagnosticItems {
storage(ArenaCacheSelector<'tcx>)
desc { "calculating the diagnostic items map in a crate" }
+ separate_provide_extern
}
query missing_lang_items(_: CrateNum) -> &'tcx [LangItem] {
desc { "calculating the missing lang items in a crate" }
+ separate_provide_extern
}
query visible_parent_map(_: ()) -> DefIdMap<DefId> {
storage(ArenaCacheSelector<'tcx>)
query missing_extern_crate_item(_: CrateNum) -> bool {
eval_always
desc { "seeing if we're missing an `extern crate` item for this crate" }
+ separate_provide_extern
}
query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
eval_always
desc { "looking at the source for a crate" }
+ separate_provide_extern
}
query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
eval_always
query is_private_dep(c: CrateNum) -> bool {
eval_always
desc { "check whether crate {} is a private dependency", c }
+ separate_provide_extern
}
query allocator_kind(_: ()) -> Option<AllocatorKind> {
eval_always
query exported_symbols(_: CrateNum)
-> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
desc { "exported_symbols" }
+ separate_provide_extern
}
query collect_and_partition_mono_items(_: ()) -> (&'tcx DefIdSet, &'tcx [CodegenUnit<'tcx>]) {
|tcx| "determining which generic parameters are unused by `{}`",
tcx.def_path_str(key.def_id())
}
+ separate_provide_extern
}
query backend_optimization_level(_: ()) -> OptLevel {
desc { "optimization level used by backend" }
use crate::mir::interpret::ConstValue;
use crate::mir::interpret::{LitToConstInput, Scalar};
-use crate::ty::{self, Ty, TyCtxt};
-use crate::ty::{ParamEnv, ParamEnvAnd};
+use crate::ty::{
+ self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
+ TyCtxt, TypeFoldable,
+};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
let ty = tcx.type_of(def.def_id_for_type_of());
+ match Self::try_eval_lit_or_param(tcx, ty, expr) {
+ Some(v) => v,
+ None => tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: def.to_global(),
+ substs_: None,
+ promoted: None,
+ }),
+ ty,
+ }),
+ }
+ }
+
+ fn try_eval_lit_or_param(
+ tcx: TyCtxt<'tcx>,
+ ty: Ty<'tcx>,
+ expr: &'tcx hir::Expr<'tcx>,
+ ) -> Option<&'tcx Self> {
let lit_input = match expr.kind {
hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
// If an error occurred, ignore that it's a literal and leave reporting the error up to
// mir.
if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
- return c;
+ return Some(c);
} else {
tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
}
};
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
- let val = match expr.kind {
+ match expr.kind {
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
// Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`.
let generics = tcx.generics_of(item_def_id.to_def_id());
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.hir().name(hir_id);
- ty::ConstKind::Param(ty::ParamConst::new(index, name))
+ Some(tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
+ ty,
+ }))
}
- _ => ty::ConstKind::Unevaluated(ty::Unevaluated {
- def: def.to_global(),
- substs_: None,
- promoted: None,
- }),
+ _ => None,
+ }
+ }
+
+ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+ debug!("Const::from_inline_const(def_id={:?})", def_id);
+
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+
+ let body_id = match tcx.hir().get(hir_id) {
+ hir::Node::AnonConst(ac) => ac.body,
+ _ => span_bug!(
+ tcx.def_span(def_id.to_def_id()),
+ "from_inline_const can only process anonymous constants"
+ ),
};
- tcx.mk_const(ty::Const { val, ty })
+ let expr = &tcx.hir().body(body_id).value;
+
+ let ty = tcx.typeck(def_id).node_type(hir_id);
+
+ let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) {
+ Some(v) => v,
+ None => {
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
+ let parent_substs =
+ tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
+ let substs =
+ InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
+ .substs;
+ tcx.mk_const(ty::Const {
+ val: ty::ConstKind::Unevaluated(ty::Unevaluated {
+ def: ty::WithOptConstParam::unknown(def_id).to_global(),
+ substs_: Some(substs),
+ promoted: None,
+ }),
+ ty,
+ })
+ }
+ };
+ debug_assert!(!ret.has_free_regions(tcx));
+ ret
}
/// Interns the given value as a constant.
// LLVM's definition of `noalias` is based solely on memory
// dependencies rather than pointer equality
//
- // Due to miscompiles in LLVM < 12, we apply a separate NoAliasMutRef attribute
- // for UniqueBorrowed arguments, so that the codegen backend can decide
- // whether or not to actually emit the attribute.
+ // Due to past miscompiles in LLVM, we apply a separate NoAliasMutRef attribute
+ // for UniqueBorrowed arguments, so that the codegen backend can decide whether
+ // or not to actually emit the attribute. It can also be controlled with the
+ // `-Zmutable-noalias` debugging option.
let no_alias = match kind {
PointerKind::Shared | PointerKind::UniqueBorrowed => false,
PointerKind::UniqueOwned => true,
Binder, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, BoundVar, BoundVariableKind,
CanonicalPolyFnSig, ClosureSubsts, ClosureSubstsParts, ConstVid, EarlyBoundRegion,
ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FnSig, FreeRegion, GenSig,
- GeneratorSubsts, GeneratorSubstsParts, ParamConst, ParamTy, PolyExistentialProjection,
- PolyExistentialTraitRef, PolyFnSig, PolyGenSig, PolyTraitRef, ProjectionTy, Region, RegionKind,
- RegionVid, TraitRef, TyKind, TypeAndMut, UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
+ GeneratorSubsts, GeneratorSubstsParts, InlineConstSubsts, InlineConstSubstsParts, ParamConst,
+ ParamTy, PolyExistentialProjection, PolyExistentialTraitRef, PolyFnSig, PolyGenSig,
+ PolyTraitRef, ProjectionTy, Region, RegionKind, RegionVid, TraitRef, TyKind, TypeAndMut,
+ UpvarSubsts, VarianceDiagInfo, VarianceDiagMutKind,
};
pub use self::trait_def::TraitDef;
| DefKind::Static
| DefKind::AssocConst
| DefKind::Ctor(..)
- | DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def),
+ | DefKind::AnonConst
+ | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
// If the caller wants `mir_for_ctfe` of a function they should not be using
// `instance_mir`, so we'll assume const fn also wants the optimized version.
_ => {
p!(print_def_path(did, substs));
if !substs.as_closure().is_valid() {
p!(" closure_substs=(unavailable)");
+ p!(write(" substs={:?}", substs));
} else {
p!(" closure_kind_ty=", print(substs.as_closure().kind_ty()));
p!(
};
}
+macro_rules! separate_provide_extern_decl {
+ ([][$name:ident]) => {
+ ()
+ };
+ ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+ for<'tcx> fn(
+ TyCtxt<'tcx>,
+ query_keys::$name<'tcx>,
+ ) -> query_values::$name<'tcx>
+ };
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ separate_provide_extern_decl!([$($modifiers)*][$($args)*])
+ };
+}
+
+macro_rules! separate_provide_extern_default {
+ ([][$name:ident]) => {
+ ()
+ };
+ ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
+ |_, key| bug!(
+ "`tcx.{}({:?})` unsupported by its crate; \
+ perhaps the `{}` query was never assigned a provider function",
+ stringify!($name),
+ key,
+ stringify!($name),
+ )
+ };
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ separate_provide_extern_default!([$($modifiers)*][$($args)*])
+ };
+}
+
macro_rules! define_callbacks {
(<$tcx:tt>
$($(#[$attr:meta])*
) -> query_values::$name<'tcx>,)*
}
+ pub struct ExternProviders {
+ $(pub $name: separate_provide_extern_decl!([$($modifiers)*][$name]),)*
+ }
+
impl Default for Providers {
fn default() -> Self {
Providers {
}
}
+ impl Default for ExternProviders {
+ fn default() -> Self {
+ ExternProviders {
+ $($name: separate_provide_extern_default!([$($modifiers)*][$name]),)*
+ }
+ }
+ }
+
impl Copy for Providers {}
impl Clone for Providers {
fn clone(&self) -> Self { *self }
}
+ impl Copy for ExternProviders {}
+ impl Clone for ExternProviders {
+ fn clone(&self) -> Self { *self }
+ }
+
pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync {
fn as_any(&'tcx self) -> &'tcx dyn std::any::Any;
})
.enumerate()
.map(|(i, r)| match r {
- Err(TypeError::Sorts(exp_found)) => Err(TypeError::ArgumentSorts(exp_found, i)),
- Err(TypeError::Mutability) => Err(TypeError::ArgumentMutability(i)),
+ Err(TypeError::Sorts(exp_found) | TypeError::ArgumentSorts(exp_found, _)) => {
+ Err(TypeError::ArgumentSorts(exp_found, i))
+ }
+ Err(TypeError::Mutability | TypeError::ArgumentMutability(_)) => {
+ Err(TypeError::ArgumentMutability(i))
+ }
r => r,
});
Ok(ty::FnSig {
}
}
+/// An inline const is modeled like
+///
+/// const InlineConst<'l0...'li, T0...Tj, R>: R;
+///
+/// where:
+///
+/// - 'l0...'li and T0...Tj are the generic parameters
+/// inherited from the item that defined the inline const,
+/// - R represents the type of the constant.
+///
+/// When the inline const is instantiated, `R` is substituted as the actual inferred
+/// type of the constant. The reason that `R` is represented as an extra type parameter
+/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters:
+/// inline const can reference lifetimes that are internal to the creating function.
+#[derive(Copy, Clone, Debug, TypeFoldable)]
+pub struct InlineConstSubsts<'tcx> {
+ /// Generic parameters from the enclosing item,
+ /// concatenated with the inferred type of the constant.
+ pub substs: SubstsRef<'tcx>,
+}
+
+/// Struct returned by `split()`.
+pub struct InlineConstSubstsParts<'tcx, T> {
+ pub parent_substs: &'tcx [GenericArg<'tcx>],
+ pub ty: T,
+}
+
+impl<'tcx> InlineConstSubsts<'tcx> {
+ /// Construct `InlineConstSubsts` from `InlineConstSubstsParts`.
+ pub fn new(
+ tcx: TyCtxt<'tcx>,
+ parts: InlineConstSubstsParts<'tcx, Ty<'tcx>>,
+ ) -> InlineConstSubsts<'tcx> {
+ InlineConstSubsts {
+ substs: tcx.mk_substs(
+ parts.parent_substs.iter().copied().chain(std::iter::once(parts.ty.into())),
+ ),
+ }
+ }
+
+ /// Divides the inline const substs into their respective components.
+ /// The ordering assumed here must match that used by `InlineConstSubsts::new` above.
+ fn split(self) -> InlineConstSubstsParts<'tcx, GenericArg<'tcx>> {
+ match self.substs[..] {
+ [ref parent_substs @ .., ty] => InlineConstSubstsParts { parent_substs, ty },
+ _ => bug!("inline const substs missing synthetics"),
+ }
+ }
+
+ /// Returns the substitutions of the inline const's parent.
+ pub fn parent_substs(self) -> &'tcx [GenericArg<'tcx>] {
+ self.split().parent_substs
+ }
+
+ /// Returns the type of this inline const.
+ pub fn ty(self) -> Ty<'tcx> {
+ self.split().ty.expect_ty()
+ }
+}
+
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable)]
pub enum ExistentialPredicate<'tcx> {
use crate::mir;
use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
-use crate::ty::sty::{ClosureSubsts, GeneratorSubsts};
+use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
use rustc_hir::def_id::DefId;
GeneratorSubsts { substs: self }
}
+ /// Interpret these substitutions as the substitutions of an inline const.
+ /// Inline const substitutions have a particular structure controlled by the
+ /// compiler that encodes information like the inferred type;
+ /// see `ty::InlineConstSubsts` struct for more comments.
+ pub fn as_inline_const(&'tcx self) -> InlineConstSubsts<'tcx> {
+ InlineConstSubsts { substs: self }
+ }
+
/// Creates an `InternalSubsts` that maps each generic parameter to itself.
pub fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx> {
Self::for_item(tcx, def_id, |param, _| tcx.mk_param_from_def(param))
matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Generator)
}
+ /// Returns `true` if `def_id` refers to a definition that does not have its own
+ /// type-checking context, i.e. closure, generator or inline const.
+ pub fn is_typeck_child(self, def_id: DefId) -> bool {
+ matches!(
+ self.def_kind(def_id),
+ DefKind::Closure | DefKind::Generator | DefKind::InlineConst
+ )
+ }
+
/// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`).
pub fn is_trait(self, def_id: DefId) -> bool {
self.def_kind(def_id) == DefKind::Trait
matches!(self.def_kind(def_id), DefKind::Ctor(..))
}
- /// Given the def-ID of a fn or closure, returns the def-ID of
- /// the innermost fn item that the closure is contained within.
- /// This is a significant `DefId` because, when we do
- /// type-checking, we type-check this fn item and all of its
- /// (transitive) closures together. Therefore, when we fetch the
+ /// Given the `DefId`, returns the `DefId` of the innermost item that
+ /// has its own type-checking context or "inference enviornment".
+ ///
+ /// For example, a closure has its own `DefId`, but it is type-checked
+ /// with the containing item. Similarly, an inline const block has its
+ /// own `DefId` but it is type-checked together with the containing item.
+ ///
+ /// Therefore, when we fetch the
/// `typeck` the closure, for example, we really wind up
/// fetching the `typeck` the enclosing fn item.
- pub fn closure_base_def_id(self, def_id: DefId) -> DefId {
+ pub fn typeck_root_def_id(self, def_id: DefId) -> DefId {
let mut def_id = def_id;
- while self.is_closure(def_id) {
+ while self.is_typeck_child(def_id) {
def_id = self.parent(def_id).unwrap_or_else(|| {
bug!("closure {:?} has no parent", def_id);
});
#![feature(once_cell)]
#![feature(min_specialization)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
- let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+ let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
ExprKind::ConstBlock { value }
}
let (lit, neg) = match expr.kind {
hir::ExprKind::ConstBlock(ref anon_const) => {
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
- let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id);
+ let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
if matches!(value.val, ConstKind::Param(_)) {
let span = self.tcx.hir().span(anon_const.hir_id);
self.errors.push(PatternError::ConstParamInPattern(span));
}
}
+ /// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled.
+ #[cfg(test)]
+ pub(crate) fn allow_unreachable(&mut self) {
+ #[cfg(debug_assertions)]
+ self.reachable_blocks.insert_all()
+ }
+
/// Returns the underlying `Results`.
pub fn results(&self) -> &Results<'tcx, A> {
&self.results.borrow()
let mut cursor =
Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body);
+ cursor.allow_unreachable();
+
let every_target = || {
body.basic_blocks()
.iter_enumerated()
use crate::{AnalysisDomain, GenKill, GenKillAnalysis};
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
-use rustc_span::DUMMY_SP;
-
-pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals<MutBorrow<'mir, 'tcx>>;
/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
/// to a given local.
///
-/// The `K` parameter determines what kind of borrows are tracked. By default,
-/// `MaybeBorrowedLocals` looks for *any* borrow of a local. If you are only interested in borrows
-/// that might allow mutation, use the `MaybeMutBorrowedLocals` type alias instead.
-///
/// At present, this is used as a very limited form of alias analysis. For example,
/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
-/// immovable generators. `MaybeMutBorrowedLocals` is used during const checking to prove that a
-/// local has not been mutated via indirect assignment (e.g., `*p = 42`), the side-effects of a
-/// function call or inline assembly.
-pub struct MaybeBorrowedLocals<K = AnyBorrow> {
- kind: K,
+/// immovable generators.
+pub struct MaybeBorrowedLocals {
ignore_borrow_on_drop: bool,
}
/// A dataflow analysis that records whether a pointer or reference exists that may alias the
/// given local.
pub fn all_borrows() -> Self {
- MaybeBorrowedLocals { kind: AnyBorrow, ignore_borrow_on_drop: false }
- }
-}
-
-impl MaybeMutBorrowedLocals<'mir, 'tcx> {
- /// A dataflow analysis that records whether a pointer or reference exists that may *mutably*
- /// alias the given local.
- ///
- /// This includes `&mut` and pointers derived from an `&mut`, as well as shared borrows of
- /// types with interior mutability.
- pub fn mut_borrows_only(
- tcx: TyCtxt<'tcx>,
- body: &'mir mir::Body<'tcx>,
- param_env: ParamEnv<'tcx>,
- ) -> Self {
- MaybeBorrowedLocals {
- kind: MutBorrow { body, tcx, param_env },
- ignore_borrow_on_drop: false,
- }
+ MaybeBorrowedLocals { ignore_borrow_on_drop: false }
}
}
-impl<K> MaybeBorrowedLocals<K> {
+impl MaybeBorrowedLocals {
/// During dataflow analysis, ignore the borrow that may occur when a place is dropped.
///
/// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a
MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self }
}
- fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T, K> {
- TransferFunction {
- kind: &self.kind,
- trans,
- ignore_borrow_on_drop: self.ignore_borrow_on_drop,
- }
+ fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
+ TransferFunction { trans, ignore_borrow_on_drop: self.ignore_borrow_on_drop }
}
}
-impl<K> AnalysisDomain<'tcx> for MaybeBorrowedLocals<K>
-where
- K: BorrowAnalysisKind<'tcx>,
-{
+impl AnalysisDomain<'tcx> for MaybeBorrowedLocals {
type Domain = BitSet<Local>;
- const NAME: &'static str = K::ANALYSIS_NAME;
+ const NAME: &'static str = "maybe_borrowed_locals";
fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
// bottom = unborrowed
}
}
-impl<K> GenKillAnalysis<'tcx> for MaybeBorrowedLocals<K>
-where
- K: BorrowAnalysisKind<'tcx>,
-{
+impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
type Idx = Local;
fn statement_effect(
}
/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
-struct TransferFunction<'a, T, K> {
+struct TransferFunction<'a, T> {
trans: &'a mut T,
- kind: &'a K,
ignore_borrow_on_drop: bool,
}
-impl<T, K> Visitor<'tcx> for TransferFunction<'a, T, K>
+impl<T> Visitor<'tcx> for TransferFunction<'a, T>
where
T: GenKill<Local>,
- K: BorrowAnalysisKind<'tcx>,
{
fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
self.super_statement(stmt, location);
self.super_rvalue(rvalue, location);
match rvalue {
- mir::Rvalue::AddressOf(mt, borrowed_place) => {
- if !borrowed_place.is_indirect() && self.kind.in_address_of(*mt, *borrowed_place) {
+ mir::Rvalue::AddressOf(_mt, borrowed_place) => {
+ if !borrowed_place.is_indirect() {
self.trans.gen(borrowed_place.local);
}
}
- mir::Rvalue::Ref(_, kind, borrowed_place) => {
- if !borrowed_place.is_indirect() && self.kind.in_ref(*kind, *borrowed_place) {
+ mir::Rvalue::Ref(_, _kind, borrowed_place) => {
+ if !borrowed_place.is_indirect() {
self.trans.gen(borrowed_place.local);
}
}
}
}
}
-
-pub struct AnyBorrow;
-
-pub struct MutBorrow<'mir, 'tcx> {
- tcx: TyCtxt<'tcx>,
- body: &'mir Body<'tcx>,
- param_env: ParamEnv<'tcx>,
-}
-
-impl MutBorrow<'mir, 'tcx> {
- /// `&` and `&raw` only allow mutation if the borrowed place is `!Freeze`.
- ///
- /// This assumes that it is UB to take the address of a struct field whose type is
- /// `Freeze`, then use pointer arithmetic to derive a pointer to a *different* field of
- /// that same struct whose type is `!Freeze`. If we decide that this is not UB, we will
- /// have to check the type of the borrowed **local** instead of the borrowed **place**
- /// below. See [rust-lang/unsafe-code-guidelines#134].
- ///
- /// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
- fn shared_borrow_allows_mutation(&self, place: Place<'tcx>) -> bool {
- !place.ty(self.body, self.tcx).ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env)
- }
-}
-
-pub trait BorrowAnalysisKind<'tcx> {
- const ANALYSIS_NAME: &'static str;
-
- fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool;
- fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool;
-}
-
-impl BorrowAnalysisKind<'tcx> for AnyBorrow {
- const ANALYSIS_NAME: &'static str = "maybe_borrowed_locals";
-
- fn in_ref(&self, _: mir::BorrowKind, _: Place<'_>) -> bool {
- true
- }
- fn in_address_of(&self, _: Mutability, _: Place<'_>) -> bool {
- true
- }
-}
-
-impl BorrowAnalysisKind<'tcx> for MutBorrow<'mir, 'tcx> {
- const ANALYSIS_NAME: &'static str = "maybe_mut_borrowed_locals";
-
- fn in_ref(&self, kind: mir::BorrowKind, place: Place<'tcx>) -> bool {
- match kind {
- mir::BorrowKind::Mut { .. } => true,
- mir::BorrowKind::Shared | mir::BorrowKind::Shallow | mir::BorrowKind::Unique => {
- self.shared_borrow_allows_mutation(place)
- }
- }
- }
-
- fn in_address_of(&self, mt: Mutability, place: Place<'tcx>) -> bool {
- match mt {
- Mutability::Mut => true,
- Mutability::Not => self.shared_borrow_allows_mutation(place),
- }
- }
-}
mod liveness;
mod storage_liveness;
-pub use self::borrowed_locals::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
+pub use self::borrowed_locals::MaybeBorrowedLocals;
pub use self::init_locals::MaybeInitializedLocals;
pub use self::liveness::MaybeLiveLocals;
pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(box_syntax)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(exact_size_is_empty)]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
use rustc_middle::ty::{self, Ty, TyCtxt};
use crate::impls::{
- DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeMutBorrowedLocals,
- MaybeUninitializedPlaces,
+ DefinitelyInitializedPlaces, MaybeInitializedPlaces, MaybeLiveLocals, MaybeUninitializedPlaces,
};
use crate::move_paths::{HasMoveData, MoveData};
use crate::move_paths::{LookupResult, MovePathIndex};
sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_def_inits);
}
- if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_indirectly_mutable).is_some() {
- let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env)
- .into_engine(tcx, body)
- .iterate_to_fixpoint();
-
- sanity_check_via_rustc_peek(tcx, body, &attributes, &flow_mut_borrowed);
- }
-
if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() {
let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
}
}
-impl<'tcx> RustcPeekAt<'tcx> for MaybeMutBorrowedLocals<'_, 'tcx> {
- fn peek_at(
- &self,
- tcx: TyCtxt<'tcx>,
- place: mir::Place<'tcx>,
- flow_state: &BitSet<Local>,
- call: PeekCall,
- ) {
- info!(?place, "peek_at");
- let Some(local) = place.as_local() else {
- tcx.sess.span_err(call.span, "rustc_peek: argument was not a local");
- return;
- };
-
- if !flow_state.contains(local) {
- tcx.sess.span_err(call.span, "rustc_peek: bit not set");
- }
- }
-}
-
impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
fn peek_at(
&self,
// Non-code expressions are injected into the coverage map, without generating executable code.
fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: CoverageKind) {
- debug_assert!(if let CoverageKind::Expression { .. } = expression { true } else { false });
+ debug_assert!(matches!(expression, CoverageKind::Expression { .. }));
debug!(" injecting non-code expression {:?}", expression);
let inject_in_bb = mir::START_BLOCK;
let data = &mut mir_body[inject_in_bb];
stmt_index: usize,
) -> Self {
let is_closure = match statement.kind {
- StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => match kind {
- AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _) => true,
- _ => false,
- },
+ StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => {
+ matches!(kind, AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _))
+ }
_ => false,
};
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![feature(let_else)]
#![feature(trusted_step)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// This pass must run before inlining, since we insert callee bodies in RevealAll mode.
// Do not apply this transformation to generators.
- if (tcx.sess.mir_opt_level() >= 3 || !super::inline::is_enabled(tcx))
+ if (tcx.sess.mir_opt_level() >= 3 || super::inline::is_enabled(tcx))
&& body.generator.is_none()
{
let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
// This is a temporary solution that handles possibly diverging asm statements.
// Accompanying testcases: mir-opt/unreachable_asm.rs and mir-opt/unreachable_asm_2.rs
let asm_stmt_in_block = || {
- bb_data.statements.iter().any(|stmt: &Statement<'_>| match stmt.kind {
- StatementKind::LlvmInlineAsm(..) => true,
- _ => false,
+ bb_data.statements.iter().any(|stmt: &Statement<'_>| {
+ matches!(stmt.kind, StatementKind::LlvmInlineAsm(..))
})
};
}
}
}
+ mir::TerminatorKind::Assert { ref msg, .. } => {
+ let lang_item = match msg {
+ mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck,
+ _ => LangItem::Panic,
+ };
+ let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source)));
+ if should_codegen_locally(tcx, &instance) {
+ self.output.push(create_fn_mono_item(tcx, instance, source));
+ }
+ }
mir::TerminatorKind::Goto { .. }
| mir::TerminatorKind::SwitchInt { .. }
| mir::TerminatorKind::Resume
| mir::TerminatorKind::Abort
| mir::TerminatorKind::Return
- | mir::TerminatorKind::Unreachable
- | mir::TerminatorKind::Assert { .. } => {}
+ | mir::TerminatorKind::Unreachable => {}
mir::TerminatorKind::GeneratorDrop
| mir::TerminatorKind::Yield { .. }
| mir::TerminatorKind::FalseEdge { .. }
#![feature(let_else)]
#![feature(in_band_lifetimes)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
generics: &'tcx ty::Generics,
unused_parameters: &FiniteBitSet<u32>,
) {
- let base_def_id = tcx.closure_base_def_id(def_id);
+ let base_def_id = tcx.typeck_root_def_id(def_id);
if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) {
return;
}
ControlFlow::CONTINUE
}
ty::ConstKind::Unevaluated(uv)
- if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst =>
+ if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) =>
{
self.visit_child_body(uv.def.did, uv.substs(self.tcx));
ControlFlow::CONTINUE
src_file.prefer_local(),
line_nos
) {
- eprintln!("Error writting to file {}", e.to_string())
+ eprintln!("Error writing to file {}", e)
}
}
}
rustc_span = { path = "../rustc_span" }
rustc_ast = { path = "../rustc_ast" }
unicode-normalization = "0.1.11"
+unicode-width = "0.1.4"
use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::token::{self, CommentKind, Token, TokenKind};
use rustc_ast::tokenstream::{Spacing, TokenStream};
+use rustc_ast::util::unicode::contains_text_flow_control_chars;
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult};
use rustc_lexer::unescape::{self, Mode};
use rustc_lexer::{Base, DocStyle, RawStrError};
-use rustc_session::lint::builtin::RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX;
+use rustc_session::lint::builtin::{
+ RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::ParseSess;
use rustc_span::symbol::{sym, Symbol};
.struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
}
+ /// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly
+ /// complain about it.
+ fn lint_unicode_text_flow(&self, start: BytePos) {
+ // Opening delimiter of the length 2 is not included into the comment text.
+ let content_start = start + BytePos(2);
+ let content = self.str_from(content_start);
+ if contains_text_flow_control_chars(content) {
+ let span = self.mk_sp(start, self.pos);
+ self.sess.buffer_lint_with_diagnostic(
+ &TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+ span,
+ ast::CRATE_NODE_ID,
+ "unicode codepoint changing visible direction of text present in comment",
+ BuiltinLintDiagnostics::UnicodeTextFlow(span, content.to_string()),
+ );
+ }
+ }
+
/// Turns simple `rustc_lexer::TokenKind` enum into a rich
/// `rustc_ast::TokenKind`. This turns strings into interned
/// symbols and runs additional validation.
Some(match token {
rustc_lexer::TokenKind::LineComment { doc_style } => {
// Skip non-doc comments
- let doc_style = doc_style?;
+ let doc_style = if let Some(doc_style) = doc_style {
+ doc_style
+ } else {
+ self.lint_unicode_text_flow(start);
+ return None;
+ };
// Opening delimiter of the length 3 is not included into the symbol.
let content_start = start + BytePos(3);
}
// Skip non-doc comments
- let doc_style = doc_style?;
+ let doc_style = if let Some(doc_style) = doc_style {
+ doc_style
+ } else {
+ self.lint_unicode_text_flow(start);
+ return None;
+ };
// Opening delimiter of the length 3 and closing delimiter of the length 2
// are not included into the symbol.
assert!(mode.is_bytes());
let (c, span) = last_char();
let mut err = handler.struct_span_err(span, "non-ASCII character in byte constant");
- err.span_label(span, "byte constant must be ASCII");
+ let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
+ format!(" but is {:?}", c)
+ } else {
+ String::new()
+ };
+ err.span_label(span, &format!("byte constant must be ASCII{}", postfix));
if (c as u32) <= 0xFF {
err.span_suggestion(
span,
&format!(
- "if you meant to use the unicode code point for '{}', use a \\xHH escape",
+ "if you meant to use the unicode code point for {:?}, use a \\xHH escape",
c
),
format!("\\x{:X}", c as u32),
err.span_suggestion(
span,
&format!(
- "if you meant to use the UTF-8 encoding of '{}', use \\xHH escapes",
+ "if you meant to use the UTF-8 encoding of {:?}, use \\xHH escapes",
c
),
utf8.as_bytes()
}
EscapeError::NonAsciiCharInByteString => {
assert!(mode.is_bytes());
- let (_c, span) = last_char();
+ let (c, span) = last_char();
+ let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
+ format!(" but is {:?}", c)
+ } else {
+ String::new()
+ };
handler
.struct_span_err(span, "raw byte string must be ASCII")
- .span_label(span, "must be ASCII")
+ .span_label(span, &format!("must be ASCII{}", postfix))
.emit();
}
EscapeError::OutOfRangeHexEscape => {
} else if self.check_fn_front_matter(def_final) {
// FUNCTION ITEM
let (ident, sig, generics, body) = self.parse_fn(attrs, req_name, lo)?;
- (ident, ItemKind::Fn(Box::new(FnKind(def(), sig, generics, body))))
+ (ident, ItemKind::Fn(Box::new(Fn { defaultness: def(), sig, generics, body })))
} else if self.eat_keyword(kw::Extern) {
if self.eat_keyword(kw::Crate) {
// EXTERN CRATE
};
let trait_ref = TraitRef { path, ref_id: ty_first.id };
- ItemKind::Impl(Box::new(ImplKind {
+ ItemKind::Impl(Box::new(Impl {
unsafety,
polarity,
defaultness,
}
None => {
// impl Type
- ItemKind::Impl(Box::new(ImplKind {
+ ItemKind::Impl(Box::new(Impl {
unsafety,
polarity,
defaultness,
self.expect_keyword(kw::Trait)?;
let ident = self.parse_ident()?;
- let mut tps = self.parse_generics()?;
+ let mut generics = self.parse_generics()?;
// Parse optional colon and supertrait bounds.
let had_colon = self.eat(&token::Colon);
}
let bounds = self.parse_generic_bounds(None)?;
- tps.where_clause = self.parse_where_clause()?;
+ generics.where_clause = self.parse_where_clause()?;
self.expect_semi()?;
let whole_span = lo.to(self.prev_token.span);
self.sess.gated_spans.gate(sym::trait_alias, whole_span);
- Ok((ident, ItemKind::TraitAlias(tps, bounds)))
+ Ok((ident, ItemKind::TraitAlias(generics, bounds)))
} else {
// It's a normal trait.
- tps.where_clause = self.parse_where_clause()?;
+ generics.where_clause = self.parse_where_clause()?;
let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?;
- Ok((ident, ItemKind::Trait(Box::new(TraitKind(is_auto, unsafety, tps, bounds, items)))))
+ Ok((
+ ident,
+ ItemKind::Trait(Box::new(Trait { is_auto, unsafety, generics, bounds, items })),
+ ))
}
}
/// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
/// ```
/// The `"type"` has already been eaten.
- fn parse_type_alias(&mut self, def: Defaultness) -> PResult<'a, ItemInfo> {
+ fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemInfo> {
let ident = self.parse_ident()?;
let mut generics = self.parse_generics()?;
if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
generics.where_clause = self.parse_where_clause()?;
- let default = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
+ let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
self.expect_semi()?;
- Ok((ident, ItemKind::TyAlias(Box::new(TyAliasKind(def, generics, bounds, default)))))
+ Ok((ident, ItemKind::TyAlias(Box::new(TyAlias { defaultness, generics, bounds, ty }))))
}
/// Parses a `UseTree`.
};
match impl_info.1 {
- ItemKind::Impl(box ImplKind {
- of_trait: Some(ref trai), ref mut constness, ..
- }) => {
+ ItemKind::Impl(box Impl { of_trait: Some(ref trai), ref mut constness, .. }) => {
*constness = Const::Yes(const_span);
let before_trait = trai.path.span.shrink_to_lo();
fn check_attributes(
&self,
hir_id: HirId,
- span: Span,
+ span: &Span,
target: Target,
item: Option<ItemLike<'_>>,
) {
sym::marker => self.check_marker(hir_id, attr, span, target),
sym::target_feature => self.check_target_feature(hir_id, attr, span, target),
sym::track_caller => {
- self.check_track_caller(hir_id, attr.span, attrs, span, target)
+ self.check_track_caller(hir_id, &attr.span, attrs, span, target)
}
sym::doc => self.check_doc_attrs(
attr,
sym::rustc_legacy_const_generics => {
self.check_rustc_legacy_const_generics(&attr, span, target, item)
}
- sym::rustc_lint_query_instability => {
- self.check_rustc_lint_query_instability(&attr, span, target)
- }
sym::rustc_clean
| sym::rustc_dirty
| sym::rustc_if_this_changed
}
/// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
- fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
+ fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Fn
| Target::Closure
E0518,
"attribute should be applied to function or closure",
)
- .span_label(span, "not a function or closure")
+ .span_label(*span, "not a function or closure")
.emit();
false
}
}
/// Checks if `#[naked]` is applied to a function definition.
- fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
+ fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Fn
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
attr.span,
"attribute should be applied to a function definition",
)
- .span_label(span, "not a function definition")
+ .span_label(*span, "not a function definition")
.emit();
false
}
}
/// Checks if `#[cmse_nonsecure_entry]` is applied to a function definition.
- fn check_cmse_nonsecure_entry(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+ fn check_cmse_nonsecure_entry(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Fn
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
attr.span,
"attribute should be applied to a function definition",
)
- .span_label(span, "not a function definition")
+ .span_label(*span, "not a function definition")
.emit();
false
}
fn check_track_caller(
&self,
hir_id: HirId,
- attr_span: Span,
+ attr_span: &Span,
attrs: &'hir [Attribute],
- span: Span,
+ span: &Span,
target: Target,
) -> bool {
match target {
_ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => {
struct_span_err!(
self.tcx.sess,
- attr_span,
+ *attr_span,
E0736,
"cannot use `#[track_caller]` with `#[naked]`",
)
_ => {
struct_span_err!(
self.tcx.sess,
- attr_span,
+ *attr_span,
E0739,
"attribute should be applied to function"
)
- .span_label(span, "not a function")
+ .span_label(*span, "not a function")
.emit();
false
}
&self,
hir_id: HirId,
attr: &Attribute,
- span: Span,
+ span: &Span,
target: Target,
) -> bool {
match target {
E0701,
"attribute can only be applied to a struct or enum"
)
- .span_label(span, "not a struct or enum")
+ .span_label(*span, "not a struct or enum")
.emit();
false
}
}
/// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
- fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
+ fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Trait => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
self.tcx
.sess
.struct_span_err(attr.span, "attribute can only be applied to a trait")
- .span_label(span, "not a trait")
+ .span_label(*span, "not a trait")
.emit();
false
}
&self,
hir_id: HirId,
attr: &Attribute,
- span: Span,
+ span: &Span,
target: Target,
) -> bool {
match target {
being phased out; it will become a hard error in \
a future release!",
)
- .span_label(span, "not a function")
+ .span_label(*span, "not a function")
.emit();
});
true
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to a function")
- .span_label(span, "not a function")
+ .span_label(*span, "not a function")
.emit();
false
}
"not a `use` item",
);
}
- err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information")
+ err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information")
.emit();
},
);
}
/// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid.
- fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) -> bool {
+ fn check_must_not_suspend(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::Struct | Target::Enum | Target::Union | Target::Trait => true,
_ => {
self.tcx
.sess
.struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait")
- .span_label(span, "is not a struct, enum, or trait")
+ .span_label(*span, "is not a struct, enum, or trait")
.emit();
false
}
}
/// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid.
- fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
+ fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target {
Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
being phased out; it will become a hard error in \
a future release!",
)
- .span_label(span, "not a function")
+ .span_label(*span, "not a function")
.emit();
});
}
}
/// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
- fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
+ fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target {
Target::ForeignFn | Target::ForeignStatic => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
}
}
- diag.span_label(span, "not a foreign function or static");
+ diag.span_label(*span, "not a foreign function or static");
diag.emit();
});
}
}
/// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
- fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
+ fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
Target::ExternCrate => true,
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
attr.span,
"attribute should be applied to an `extern crate` item",
)
- .span_label(span, "not an `extern crate` item")
+ .span_label(*span, "not an `extern crate` item")
.emit();
false
}
&self,
hir_id: HirId,
attr: &Attribute,
- span: Span,
+ span: &Span,
target: Target,
) -> bool {
match target {
attr.span,
"attribute should be applied to a free function, impl method or static",
)
- .span_label(span, "not a free function, impl method or static")
+ .span_label(*span, "not a free function, impl method or static")
.emit();
false
}
fn check_rustc_layout_scalar_valid_range(
&self,
attr: &Attribute,
- span: Span,
+ span: &Span,
target: Target,
) -> bool {
if target != Target::Struct {
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to a struct")
- .span_label(span, "not a struct")
+ .span_label(*span, "not a struct")
.emit();
return false;
}
fn check_rustc_legacy_const_generics(
&self,
attr: &Attribute,
- span: Span,
+ span: &Span,
target: Target,
item: Option<ItemLike<'_>>,
) -> bool {
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to a function")
- .span_label(span, "not a function")
+ .span_label(*span, "not a function")
.emit();
return false;
}
}
}
- fn check_rustc_lint_query_instability(
- &self,
- attr: &Attribute,
- span: Span,
- target: Target,
- ) -> bool {
- let is_function = matches!(target, Target::Fn | Target::Method(..));
- if !is_function {
- self.tcx
- .sess
- .struct_span_err(attr.span, "attribute should be applied to a function")
- .span_label(span, "not a function")
- .emit();
- false
- } else {
- true
- }
- }
-
/// Checks that the dep-graph debugging attributes are only present when the query-dep-graph
/// option is passed to the compiler.
fn check_rustc_dirty_clean(&self, attr: &Attribute) -> bool {
}
/// Checks if `#[link_section]` is applied to a function or static.
- fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
+ fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target {
Target::Static | Target::Fn | Target::Method(..) => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
being phased out; it will become a hard error in \
a future release!",
)
- .span_label(span, "not a function or static")
+ .span_label(*span, "not a function or static")
.emit();
});
}
}
/// Checks if `#[no_mangle]` is applied to a function or static.
- fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
+ fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
match target {
Target::Static | Target::Fn => {}
Target::Method(..) if self.is_impl_item(hir_id) => {}
being phased out; it will become a hard error in \
a future release!",
)
- .span_label(span, format!("foreign {}", foreign_item_kind))
+ .span_label(*span, format!("foreign {}", foreign_item_kind))
.note("symbol names in extern blocks are not mangled")
.span_suggestion(
attr.span,
being phased out; it will become a hard error in \
a future release!",
)
- .span_label(span, "not a free function, impl method or static")
+ .span_label(*span, "not a free function, impl method or static")
.emit();
});
}
fn check_repr(
&self,
attrs: &'hir [Attribute],
- span: Span,
+ span: &Span,
target: Target,
item: Option<ItemLike<'_>>,
hir_id: HirId,
"{}",
&format!("attribute should be applied to {} {}", article, allowed_targets)
)
- .span_label(span, &format!("not {} {}", article, allowed_targets))
+ .span_label(*span, &format!("not {} {}", article, allowed_targets))
.emit();
}
&self,
hir_id: HirId,
attr: &Attribute,
- span: Span,
+ span: &Span,
target: Target,
attrs: &[Attribute],
) -> bool {
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to a macro")
- .span_label(span, "not a macro")
+ .span_label(*span, "not a macro")
.emit();
false
}
&self,
hir_id: HirId,
attr: &Attribute,
- span: Span,
+ span: &Span,
target: Target,
) -> bool {
match target {
self.tcx
.sess
.struct_span_err(attr.span, "attribute should be applied to `const fn`")
- .span_label(span, "not a `const fn`")
+ .span_label(*span, "not a `const fn`")
.emit();
false
}
fn check_default_method_body_is_const(
&self,
attr: &Attribute,
- span: Span,
+ span: &Span,
target: Target,
) -> bool {
match target {
attr.span,
"attribute should be applied to a trait method with body",
)
- .span_label(span, "not a trait method or missing a body")
+ .span_label(*span, "not a trait method or missing a body")
.emit();
false
}
}
}
- fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
+ fn check_stability_promotable(&self, attr: &Attribute, _span: &Span, target: Target) -> bool {
match target {
Target::Expression => {
self.tcx
}
}
- fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) {
+ fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: &Span, target: Target) {
match target {
Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
}
let target = Target::from_item(item);
- self.check_attributes(item.hir_id(), item.span, target, Some(ItemLike::Item(item)));
+ self.check_attributes(item.hir_id(), &item.span, target, Some(ItemLike::Item(item)));
intravisit::walk_item(self, item)
}
fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) {
let target = Target::from_generic_param(generic_param);
- self.check_attributes(generic_param.hir_id, generic_param.span, target, None);
+ self.check_attributes(generic_param.hir_id, &generic_param.span, target, None);
intravisit::walk_generic_param(self, generic_param)
}
fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) {
let target = Target::from_trait_item(trait_item);
- self.check_attributes(trait_item.hir_id(), trait_item.span, target, None);
+ self.check_attributes(trait_item.hir_id(), &trait_item.span, target, None);
intravisit::walk_trait_item(self, trait_item)
}
fn visit_field_def(&mut self, struct_field: &'tcx hir::FieldDef<'tcx>) {
- self.check_attributes(struct_field.hir_id, struct_field.span, Target::Field, None);
+ self.check_attributes(struct_field.hir_id, &struct_field.span, Target::Field, None);
intravisit::walk_field_def(self, struct_field);
}
fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
- self.check_attributes(arm.hir_id, arm.span, Target::Arm, None);
+ self.check_attributes(arm.hir_id, &arm.span, Target::Arm, None);
intravisit::walk_arm(self, arm);
}
let target = Target::from_foreign_item(f_item);
self.check_attributes(
f_item.hir_id(),
- f_item.span,
+ &f_item.span,
target,
Some(ItemLike::ForeignItem(f_item)),
);
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
let target = target_from_impl_item(self.tcx, impl_item);
- self.check_attributes(impl_item.hir_id(), impl_item.span, target, None);
+ self.check_attributes(impl_item.hir_id(), &impl_item.span, target, None);
intravisit::walk_impl_item(self, impl_item)
}
fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
// When checking statements ignore expressions, they will be checked later.
if let hir::StmtKind::Local(ref l) = stmt.kind {
- self.check_attributes(l.hir_id, stmt.span, Target::Statement, None);
+ self.check_attributes(l.hir_id, &stmt.span, Target::Statement, None);
}
intravisit::walk_stmt(self, stmt)
}
_ => Target::Expression,
};
- self.check_attributes(expr.hir_id, expr.span, target, None);
+ self.check_attributes(expr.hir_id, &expr.span, target, None);
intravisit::walk_expr(self, expr)
}
generics: &'tcx hir::Generics<'tcx>,
item_id: HirId,
) {
- self.check_attributes(variant.id, variant.span, Target::Variant, None);
+ self.check_attributes(variant.id, &variant.span, Target::Variant, None);
intravisit::walk_variant(self, variant, generics, item_id)
}
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
- self.check_attributes(param.hir_id, param.span, Target::Param, None);
+ self.check_attributes(param.hir_id, ¶m.span, Target::Param, None);
intravisit::walk_param(self, param);
}
let check_attr_visitor = &mut CheckAttrVisitor { tcx };
tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
if module_def_id.is_top_level_module() {
- check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
+ check_attr_visitor.check_attributes(CRATE_HIR_ID, &DUMMY_SP, Target::Mod, None);
check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
}
}
required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect();
match missing_gates.as_slice() {
- &[] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(),
+ [] => struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(),
- &[missing_primary, ref missing_secondary @ ..] => {
- let mut err = feature_err(&tcx.sess.parse_sess, missing_primary, span, &msg);
+ [missing_primary, ref missing_secondary @ ..] => {
+ let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg);
// If multiple feature gates would be required to enable this expression, include
// them as help messages. Don't emit a separate error for each missing feature gate.
#![feature(nll)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_middle;
// properly, we can't miss any types.
match expr.kind {
- // Manually recurse over closures, because they are the only
+ // Manually recurse over closures and inline consts, because they are the only
// case of nested bodies that share the parent environment.
- hir::ExprKind::Closure(.., body, _, _) => {
+ hir::ExprKind::Closure(.., body, _, _)
+ | hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
let body = visitor.tcx.hir().body(body);
visitor.visit_body(body);
}
}
fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
- let closure_base_def_id = tcx.closure_base_def_id(def_id);
- if closure_base_def_id != def_id {
- return tcx.region_scope_tree(closure_base_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ if typeck_root_def_id != def_id {
+ return tcx.region_scope_tree(typeck_root_def_id);
}
let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
#![feature(try_blocks)]
#![feature(associated_type_defaults)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
use rustc_ast::MacroDef;
use rustc_attr as attr;
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::GlobalAsm
| DefKind::Impl
#![feature(once_cell)]
#![feature(rustc_attrs)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
#[macro_use]
extern crate rustc_middle;
-use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_errors::DiagnosticBuilder;
use rustc_middle::arena::Arena;
-use rustc_middle::dep_graph::{self, DepKindStruct};
+use rustc_middle::dep_graph::{self, DepKindStruct, SerializedDepNodeIndex};
use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
-use rustc_middle::ty::query::{Providers, QueryEngine};
+use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine};
use rustc_middle::ty::{self, TyCtxt};
-use rustc_query_system::ich::StableHashingContext;
+use rustc_span::def_id::LocalDefId;
use rustc_span::Span;
#[macro_use]
mod values;
use self::values::Value;
-use rustc_query_system::query::QueryAccessors;
pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::QueryDescription;
+pub(crate) use rustc_query_system::query::{QueryDescription, QueryVtable};
mod on_disk_cache;
pub use on_disk_cache::OnDiskCache;
mod util;
+fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
+ if def_id.is_top_level_module() {
+ "top-level module".to_string()
+ } else {
+ format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
+ }
+}
+
rustc_query_append! { [define_queries!][<'tcx>] }
impl<'tcx> Queries<'tcx> {
) -> FileEncodeResult
where
CTX: QueryContext + 'tcx,
- Q: super::QueryDescription<CTX> + super::QueryAccessors<CTX>,
+ Q: super::QueryDescription<CTX>,
Q::Value: Encodable<CacheEncoder<'a, 'tcx, FileEncoder>>,
{
let _timer = tcx
if res.is_err() {
return;
}
- if Q::cache_on_disk(tcx, &key) {
+ if Q::cache_on_disk(*tcx.dep_context(), &key) {
let dep_node = SerializedDepNodeIndex::new(dep_node.index());
// Record position of the cache entry.
//! generate the actual methods on tcx which find and execute the provider,
//! manage the caches, and so forth.
-use crate::{on_disk_cache, queries, Queries};
+use crate::{on_disk_cache, Queries};
use rustc_middle::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex};
use rustc_middle::ty::tls::{self, ImplicitCtxt};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::TyCtxt;
use rustc_query_system::dep_graph::HasDepContext;
-use rustc_query_system::query::{
- QueryContext, QueryDescription, QueryJobId, QueryMap, QuerySideEffects,
-};
+use rustc_query_system::query::{QueryContext, QueryJobId, QueryMap, QuerySideEffects};
use rustc_data_structures::sync::Lock;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::{Diagnostic, Handler};
use rustc_serialize::opaque;
-use rustc_span::def_id::LocalDefId;
use std::any::Any;
};
}
+macro_rules! get_provider {
+ ([][$tcx:expr, $name:ident, $key:expr]) => {{
+ $tcx.queries.local_providers.$name
+ }};
+ ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{
+ if $key.query_crate_is_local() {
+ $tcx.queries.local_providers.$name
+ } else {
+ $tcx.queries.extern_providers.$name
+ }
+ }};
+ ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
+ get_provider!([$($modifiers)*][$($args)*])
+ };
+}
+
macro_rules! define_queries {
(<$tcx:tt>
$($(#[$attr:meta])*
const NAME: &'static str = stringify!($name);
}
- impl<$tcx> QueryAccessors<QueryCtxt<$tcx>> for queries::$name<$tcx> {
- const ANON: bool = is_anon!([$($modifiers)*]);
- const EVAL_ALWAYS: bool = is_eval_always!([$($modifiers)*]);
- const DEP_KIND: dep_graph::DepKind = dep_graph::DepKind::$name;
- const HASH_RESULT: Option<fn(&mut StableHashingContext<'_>, &Self::Value) -> Fingerprint> = hash_result!([$($modifiers)*]);
+ impl<$tcx> QueryDescription<QueryCtxt<$tcx>> for queries::$name<$tcx> {
+ rustc_query_description! { $name<$tcx> }
type Cache = query_storage::$name<$tcx>;
}
#[inline]
- fn compute_fn(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
- fn(TyCtxt<'tcx>, Self::Key) -> Self::Value
+ fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
+ QueryVtable<QueryCtxt<$tcx>, Self::Key, Self::Value>
{
- if key.query_crate_is_local() {
- tcx.queries.local_providers.$name
- } else {
- tcx.queries.extern_providers.$name
+ let compute = get_provider!([$($modifiers)*][tcx, $name, key]);
+ let cache_on_disk = Self::cache_on_disk(tcx.tcx, key);
+ QueryVtable {
+ anon: is_anon!([$($modifiers)*]),
+ eval_always: is_eval_always!([$($modifiers)*]),
+ dep_kind: dep_graph::DepKind::$name,
+ hash_result: hash_result!([$($modifiers)*]),
+ handle_cycle_error: |tcx, mut error| handle_cycle_error!([$($modifiers)*][tcx, error]),
+ compute,
+ cache_on_disk,
+ try_load_from_disk: Self::TRY_LOAD_FROM_DISK,
}
}
-
- fn handle_cycle_error(
- tcx: QueryCtxt<'tcx>,
- mut error: DiagnosticBuilder<'_>,
- ) -> Self::Value {
- handle_cycle_error!([$($modifiers)*][tcx, error])
- }
})*
#[allow(nonstandard_style)]
debug_assert!(tcx.dep_graph.is_green(&dep_node));
let key = recover(tcx, dep_node).unwrap_or_else(|| panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash));
- let tcx = QueryCtxt::from_tcx(tcx);
if queries::$name::cache_on_disk(tcx, &key) {
let _ = tcx.$name(key);
}
input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
pub struct Queries<$tcx> {
local_providers: Box<Providers>,
- extern_providers: Box<Providers>,
+ extern_providers: Box<ExternProviders>,
pub on_disk_cache: Option<OnDiskCache<$tcx>>,
impl<$tcx> Queries<$tcx> {
pub fn new(
local_providers: Providers,
- extern_providers: Providers,
+ extern_providers: ExternProviders,
on_disk_cache: Option<OnDiskCache<$tcx>>,
) -> Self {
Queries {
}
};
}
-
-fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
- if def_id.is_top_level_module() {
- "top-level module".to_string()
- } else {
- format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
- }
-}
-
-rustc_query_description! {}
use crate::ich;
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::definitions::{DefPathHash, Definitions};
-use rustc_index::vec::IndexVec;
use rustc_session::cstore::CrateStore;
use rustc_session::Session;
use rustc_span::source_map::SourceMap;
Traverse {
hash_bodies: bool,
owner: LocalDefId,
- bodies: &'tcx IndexVec<hir::ItemLocalId, Option<&'tcx hir::Body<'tcx>>>,
+ bodies: &'tcx SortedMap<hir::ItemLocalId, &'tcx hir::Body<'tcx>>,
},
}
&mut self,
hash_bodies: bool,
owner: LocalDefId,
- bodies: &'a IndexVec<hir::ItemLocalId, Option<&'a hir::Body<'a>>>,
+ bodies: &'a SortedMap<hir::ItemLocalId, &'a hir::Body<'a>>,
f: impl FnOnce(&mut Self),
) {
let prev = self.body_resolver;
BodyResolver::Traverse { hash_bodies: false, .. } => {}
BodyResolver::Traverse { hash_bodies: true, owner, bodies } => {
assert_eq!(id.hir_id.owner, owner);
- bodies[id.hir_id.local_id].unwrap().hash_stable(hcx, hasher);
+ bodies[&id.hir_id.local_id].hash_stable(hcx, hasher);
}
}
}
#![feature(let_else)]
#![feature(min_specialization)]
#![feature(thread_local_const_init)]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
type Stored: Clone;
}
-pub(crate) struct QueryVtable<CTX: QueryContext, K, V> {
+pub struct QueryVtable<CTX: QueryContext, K, V> {
pub anon: bool,
pub dep_kind: CTX::DepKind,
pub eval_always: bool,
+ pub cache_on_disk: bool,
pub compute: fn(CTX::DepContext, K) -> V,
pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
- pub cache_on_disk: fn(CTX, &K) -> bool,
- pub try_load_from_disk: fn(CTX, SerializedDepNodeIndex) -> Option<V>,
+ pub try_load_from_disk: Option<fn(CTX, SerializedDepNodeIndex) -> Option<V>>,
}
impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> {
(self.compute)(tcx, key)
}
- pub(crate) fn cache_on_disk(&self, tcx: CTX, key: &K) -> bool {
- (self.cache_on_disk)(tcx, key)
- }
-
pub(crate) fn try_load_from_disk(&self, tcx: CTX, index: SerializedDepNodeIndex) -> Option<V> {
- (self.try_load_from_disk)(tcx, index)
+ self.try_load_from_disk
+ .expect("QueryDescription::load_from_disk() called for an unsupported query.")(
+ tcx, index,
+ )
}
}
-pub trait QueryAccessors<CTX: QueryContext>: QueryConfig {
- const ANON: bool;
- const EVAL_ALWAYS: bool;
- const DEP_KIND: CTX::DepKind;
- const HASH_RESULT: Option<
- fn(hcx: &mut StableHashingContext<'_>, result: &Self::Value) -> Fingerprint,
- >;
+pub trait QueryDescription<CTX: QueryContext>: QueryConfig {
+ const TRY_LOAD_FROM_DISK: Option<fn(CTX, SerializedDepNodeIndex) -> Option<Self::Value>>;
type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
+ fn describe(tcx: CTX, key: Self::Key) -> String;
+
// Don't use this method to access query results, instead use the methods on TyCtxt
fn query_state<'a>(tcx: CTX) -> &'a QueryState<CTX::DepKind, Self::Key>
where
CTX: 'a;
// Don't use this method to compute query results, instead use the methods on TyCtxt
- fn compute_fn(tcx: CTX, key: &Self::Key) -> fn(CTX::DepContext, Self::Key) -> Self::Value;
-
- fn handle_cycle_error(tcx: CTX, diag: DiagnosticBuilder<'_>) -> Self::Value;
-}
-
-pub trait QueryDescription<CTX: QueryContext>: QueryAccessors<CTX> {
- fn describe(tcx: CTX, key: Self::Key) -> String;
+ fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVtable<CTX, Self::Key, Self::Value>;
- #[inline]
- fn cache_on_disk(_: CTX, _: &Self::Key) -> bool {
- false
- }
-
- fn try_load_from_disk(_: CTX, _: SerializedDepNodeIndex) -> Option<Self::Value> {
- panic!("QueryDescription::load_from_disk() called for an unsupported query.")
- }
-}
-
-pub(crate) trait QueryVtableExt<CTX: QueryContext, K, V> {
- fn make_vtable(tcx: CTX, key: &K) -> QueryVtable<CTX, K, V>;
-}
-
-impl<CTX, Q> QueryVtableExt<CTX, Q::Key, Q::Value> for Q
-where
- CTX: QueryContext,
- Q: QueryDescription<CTX>,
-{
- fn make_vtable(tcx: CTX, key: &Q::Key) -> QueryVtable<CTX, Q::Key, Q::Value> {
- QueryVtable {
- anon: Q::ANON,
- dep_kind: Q::DEP_KIND,
- eval_always: Q::EVAL_ALWAYS,
- hash_result: Q::HASH_RESULT,
- compute: Q::compute_fn(tcx, key),
- handle_cycle_error: Q::handle_cycle_error,
- cache_on_disk: Q::cache_on_disk,
- try_load_from_disk: Q::try_load_from_disk,
- }
- }
+ fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool;
}
};
mod config;
-pub use self::config::{QueryAccessors, QueryConfig, QueryDescription};
+pub use self::config::{QueryConfig, QueryDescription, QueryVtable};
use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams};
use crate::query::caches::QueryCache;
-use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt};
+use crate::query::config::{QueryDescription, QueryVtable};
use crate::query::job::{
report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
};
// First we try to load the result from the on-disk cache.
// Some things are never cached on disk.
- if query.cache_on_disk(tcx, key) {
+ if query.cache_on_disk {
let prof_timer = tcx.dep_context().profiler().incr_cache_loading();
let result = query.try_load_from_disk(tcx, prev_dep_node_index);
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
if let Some(result) = result {
+ let prev_fingerprint = tcx
+ .dep_context()
+ .dep_graph()
+ .prev_fingerprint_of(dep_node)
+ .unwrap_or(Fingerprint::ZERO);
// If `-Zincremental-verify-ich` is specified, re-hash results from
// the cache and make sure that they have the expected fingerprint.
- if unlikely!(tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich) {
+ //
+ // If not, we still seek to verify a subset of fingerprints loaded
+ // from disk. Re-hashing results is fairly expensive, so we can't
+ // currently afford to verify every hash. This subset should still
+ // give us some coverage of potential bugs though.
+ let try_verify = prev_fingerprint.as_value().1 % 32 == 0;
+ if unlikely!(
+ try_verify || tcx.dep_context().sess().opts.debugging_opts.incremental_verify_ich
+ ) {
incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
}
Q::Key: DepNodeParams<CTX::DepContext>,
CTX: QueryContext,
{
- assert!(!Q::ANON);
-
// We may be concurrently trying both execute and force a query.
// Ensure that only one of them runs the query.
let cache = Q::query_cache(tcx);
let query = Q::make_vtable(tcx, &key);
let state = Q::query_state(tcx);
+ debug_assert!(!query.anon);
+
try_execute_query(tcx, state, cache, DUMMY_SP, key, lookup, Some(dep_node), &query);
}
use rustc_ast::visit::{self, AssocCtxt, Visitor};
use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
-use rustc_ast::{Block, FnKind, ForeignItem, ForeignItemKind, ImplKind, Item, ItemKind, NodeId};
+use rustc_ast::{Block, Fn, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_attr as attr;
use rustc_data_structures::sync::Lrc;
} else {
def_key.disambiguated_data.data.get_opt_name().expect("module without name")
};
- let expn_id = if def_kind == DefKind::Mod {
- self.cstore().module_expansion_untracked(def_id, &self.session)
- } else {
- // FIXME: Parent expansions for enums and traits are not kept in metadata.
- ExpnId::root()
- };
Some(self.new_module(
parent,
ModuleKind::Def(def_kind, def_id, name),
- expn_id,
+ self.cstore().module_expansion_untracked(def_id, &self.session),
self.cstore().get_span_untracked(def_id, &self.session),
// FIXME: Account for `#[no_implicit_prelude]` attributes.
parent.map_or(false, |module| module.no_implicit_prelude),
}
// These items do not add names to modules.
- ItemKind::Impl(box ImplKind { of_trait: Some(..), .. }) => {
+ ItemKind::Impl(box Impl { of_trait: Some(..), .. }) => {
self.r.trait_impl_items.insert(local_def_id);
}
ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::Field
| DefKind::LifetimeParam
| DefKind::GlobalAsm
if ctxt == AssocCtxt::Trait {
let (def_kind, ns) = match item.kind {
AssocItemKind::Const(..) => (DefKind::AssocConst, ValueNS),
- AssocItemKind::Fn(box FnKind(_, ref sig, _, _)) => {
+ AssocItemKind::Fn(box Fn { ref sig, .. }) => {
if sig.decl.has_self() {
self.r.has_self.insert(def_id);
}
pub descr: &'static str,
pub path: Path,
pub accessible: bool,
+ /// An extra note that should be issued if this item is suggested
+ pub note: Option<String>,
}
/// Adjust the impl span so that just the `impl` keyword is taken by removing
err.span_label(span, label);
if let Some((suggestions, msg, applicability)) = suggestion {
+ if suggestions.is_empty() {
+ err.help(&msg);
+ return err;
+ }
err.multipart_suggestion(&msg, suggestions, applicability);
}
return;
}
+ // #90113: Do not count an inaccessible reexported item as a candidate.
+ if let NameBindingKind::Import { binding, .. } = name_binding.kind {
+ if this.is_accessible_from(binding.vis, parent_scope.module)
+ && !this.is_accessible_from(name_binding.vis, parent_scope.module)
+ {
+ return;
+ }
+ }
+
// collect results based on the filter function
// avoid suggesting anything from the same module in which we are resolving
+ // avoid suggesting anything with a hygienic name
if ident.name == lookup_ident.name
&& ns == namespace
&& !ptr::eq(in_module, parent_scope.module)
+ && !ident.span.normalize_to_macros_2_0().from_expansion()
{
let res = name_binding.res();
if filter_fn(res) {
}
if candidates.iter().all(|v: &ImportSuggestion| v.did != did) {
+ // See if we're recommending TryFrom, TryInto, or FromIterator and add
+ // a note about editions
+ let note = if let Some(did) = did {
+ let requires_note = !did.is_local()
+ && this.cstore().item_attrs(did, this.session).iter().any(
+ |attr| {
+ if attr.has_name(sym::rustc_diagnostic_item) {
+ [sym::TryInto, sym::TryFrom, sym::FromIterator]
+ .map(|x| Some(x))
+ .contains(&attr.value_str())
+ } else {
+ false
+ }
+ },
+ );
+
+ requires_note.then(|| {
+ format!(
+ "'{}' is included in the prelude starting in Edition 2021",
+ path_names_to_string(&path)
+ )
+ })
+ } else {
+ None
+ };
+
candidates.push(ImportSuggestion {
did,
descr: res.descr(),
path,
accessible: child_accessible,
+ note,
});
}
}
(b1, b2, misc1, misc2, false)
};
- let mut err = struct_span_err!(
- self.session,
- ident.span,
- E0659,
- "`{ident}` is ambiguous ({why})",
- why = kind.descr()
- );
+ let mut err = struct_span_err!(self.session, ident.span, E0659, "`{ident}` is ambiguous");
err.span_label(ident.span, "ambiguous name");
+ err.note(&format!("ambiguous because of {}", kind.descr()));
let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
return;
}
- let mut accessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
- let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>)> = Vec::new();
+ let mut accessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
+ Vec::new();
+ let mut inaccessible_path_strings: Vec<(String, &str, Option<DefId>, &Option<String>)> =
+ Vec::new();
candidates.iter().for_each(|c| {
(if c.accessible { &mut accessible_path_strings } else { &mut inaccessible_path_strings })
- .push((path_names_to_string(&c.path), c.descr, c.did))
+ .push((path_names_to_string(&c.path), c.descr, c.did, &c.note))
});
// we want consistent results across executions, but candidates are produced
let instead = if instead { " instead" } else { "" };
let mut msg = format!("consider importing {} {}{}", determiner, kind, instead);
+ for note in accessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
+ err.note(note);
+ }
+
if let Some(span) = use_placement_span {
for candidate in &mut accessible_path_strings {
// produce an additional newline to separate the new use statement
assert!(!inaccessible_path_strings.is_empty());
if inaccessible_path_strings.len() == 1 {
- let (name, descr, def_id) = &inaccessible_path_strings[0];
+ let (name, descr, def_id, note) = &inaccessible_path_strings[0];
let msg = format!("{} `{}` exists but is inaccessible", descr, name);
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
} else {
err.note(&msg);
}
+ if let Some(note) = (*note).as_deref() {
+ err.note(note);
+ }
} else {
- let (_, descr_first, _) = &inaccessible_path_strings[0];
+ let (_, descr_first, _, _) = &inaccessible_path_strings[0];
let descr = if inaccessible_path_strings
.iter()
.skip(1)
- .all(|(_, descr, _)| descr == descr_first)
+ .all(|(_, descr, _, _)| descr == descr_first)
{
descr_first.to_string()
} else {
let mut has_colon = false;
let mut spans = Vec::new();
- for (name, _, def_id) in &inaccessible_path_strings {
+ for (name, _, def_id, _) in &inaccessible_path_strings {
if let Some(local_def_id) = def_id.and_then(|did| did.as_local()) {
let span = definitions.def_span(local_def_id);
let span = session.source_map().guess_head_span(span);
multi_span.push_span_label(span, format!("`{}`: not accessible", name));
}
+ for note in inaccessible_path_strings.iter().map(|cand| cand.3.as_ref()).flatten() {
+ err.note(note);
+ }
+
err.span_note(multi_span, &msg);
}
}
}
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
match foreign_item.kind {
- ForeignItemKind::Fn(box FnKind(_, _, ref generics, _))
- | ForeignItemKind::TyAlias(box TyAliasKind(_, ref generics, ..)) => {
+ ForeignItemKind::Fn(box Fn { ref generics, .. })
+ | ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_foreign_item(this, foreign_item);
});
debug!("(resolving item) resolving {} ({:?})", name, item.kind);
match item.kind {
- ItemKind::TyAlias(box TyAliasKind(_, ref generics, _, _))
- | ItemKind::Fn(box FnKind(_, _, ref generics, _)) => {
+ ItemKind::TyAlias(box TyAlias { ref generics, .. })
+ | ItemKind::Fn(box Fn { ref generics, .. }) => {
self.compute_num_lifetime_params(item.id, generics);
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
visit::walk_item(this, item)
self.resolve_adt(item, generics);
}
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
ref generics,
ref of_trait,
ref self_ty,
self.resolve_implementation(generics, of_trait, &self_ty, item.id, impl_items);
}
- ItemKind::Trait(box TraitKind(.., ref generics, ref bounds, ref trait_items)) => {
+ ItemKind::Trait(box Trait { ref generics, ref bounds, ref items, .. }) => {
self.compute_num_lifetime_params(item.id, generics);
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
});
};
- this.with_trait_items(trait_items, |this| {
- for item in trait_items {
+ this.with_trait_items(items, |this| {
+ for item in items {
match &item.kind {
AssocItemKind::Const(_, ty, default) => {
this.visit_ty(ty);
);
}
}
- AssocItemKind::Fn(box FnKind(_, _, generics, _)) => {
+ AssocItemKind::Fn(box Fn { generics, .. }) => {
walk_assoc_item(this, generics, item);
}
- AssocItemKind::TyAlias(box TyAliasKind(_, generics, _, _)) => {
+ AssocItemKind::TyAlias(box TyAlias { generics, .. }) => {
walk_assoc_item(this, generics, item);
}
AssocItemKind::MacCall(_) => {
},
);
}
- AssocItemKind::Fn(box FnKind(.., generics, _)) => {
+ AssocItemKind::Fn(box Fn { generics, .. }) => {
debug!("resolve_implementation AssocItemKind::Fn");
// We also need a new scope for the impl item type parameters.
this.with_generic_param_rib(
},
);
}
- AssocItemKind::TyAlias(box TyAliasKind(
- _,
- generics,
- _,
- _,
- )) => {
+ AssocItemKind::TyAlias(box TyAlias {
+ generics, ..
+ }) => {
debug!("resolve_implementation AssocItemKind::TyAlias");
// We also need a new scope for the impl item type parameters.
this.with_generic_param_rib(
let candidates = self
.r
.lookup_import_candidates(ident, ns, &self.parent_scope, is_expected)
- .drain(..)
+ .into_iter()
.filter(|ImportSuggestion { did, .. }| {
match (did, res.and_then(|res| res.opt_def_id())) {
(Some(suggestion_did), Some(actual_did)) => *suggestion_did != actual_did,
if assoc_item.ident == ident {
return Some(match &assoc_item.kind {
ast::AssocItemKind::Const(..) => AssocSuggestion::AssocConst,
- ast::AssocItemKind::Fn(box ast::FnKind(_, sig, ..))
- if sig.decl.has_self() =>
- {
+ ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) if sig.decl.has_self() => {
AssocSuggestion::MethodWithSelf
}
ast::AssocItemKind::Fn(..) => AssocSuggestion::AssocFn,
} else {
// Search in module.
let mod_path = &path[..path.len() - 1];
- if let PathResult::Module(module) =
+ if let PathResult::Module(ModuleOrUniformRoot::Module(module)) =
self.resolve_path(mod_path, Some(TypeNS), false, span, CrateLint::No)
{
- if let ModuleOrUniformRoot::Module(module) = module {
- self.r.add_module_candidates(module, &mut names, &filter_fn);
- }
+ self.r.add_module_candidates(module, &mut names, &filter_fn);
}
}
descr: "module",
path,
accessible: true,
+ note: None,
},
));
} else {
if suggest_only_tuple_variants {
// Suggest only tuple variants regardless of whether they have fields and do not
// suggest path with added parentheses.
- let mut suggestable_variants = variants
+ let suggestable_variants = variants
.iter()
.filter(|(.., kind)| *kind == CtorKind::Fn)
.map(|(variant, ..)| path_names_to_string(variant))
err.span_suggestions(
span,
&msg,
- suggestable_variants.drain(..),
+ suggestable_variants.into_iter(),
Applicability::MaybeIncorrect,
);
}
);
}
- let mut suggestable_variants_with_placeholders = variants
+ let suggestable_variants_with_placeholders = variants
.iter()
.filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind))
.map(|(variant, _, kind)| (path_names_to_string(variant), kind))
err.span_suggestions(
span,
msg,
- suggestable_variants_with_placeholders.drain(..),
+ suggestable_variants_with_placeholders.into_iter(),
Applicability::HasPlaceholders,
);
}
def_id: LocalDefId,
) -> Option<(LocalDefId, &'tcx FxHashSet<ItemLocalId>)> {
match tcx.def_kind(def_id) {
- DefKind::AnonConst => {
+ DefKind::AnonConst | DefKind::InlineConst => {
let mut def_id = tcx
.parent(def_id.to_def_id())
.unwrap_or_else(|| bug!("anon const or closure without a parent"));
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) = c
.generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
- })
+ .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param);
let (lifetimes, binders): (FxIndexMap<hir::ParamName, Region>, Vec<_>) =
bound_generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
+ .filter(|param| {
+ matches!(param.kind, GenericParamKind::Lifetime { .. })
})
.enumerate()
.map(|(late_bound_idx, param)| {
let binders_iter = trait_ref
.bound_generic_params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. } => Some(param),
- _ => None,
- })
+ .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(
break;
}
}
- hir::TyKind::Path(ref qpath) => {
- if let QPath::Resolved(_, path) = qpath {
- let last_segment = &path.segments[path.segments.len() - 1];
- let generics = last_segment.args();
- for arg in generics.args.iter() {
- if let GenericArg::Lifetime(lt) = arg {
- if lt.name.ident() == name {
- elide_use = Some(lt.span);
- break;
- }
+ hir::TyKind::Path(QPath::Resolved(_, path)) => {
+ let last_segment = &path.segments[path.segments.len() - 1];
+ let generics = last_segment.args();
+ for arg in generics.args.iter() {
+ if let GenericArg::Lifetime(lt) = arg {
+ if lt.name.ident() == name {
+ elide_use = Some(lt.span);
+ break;
}
}
- break;
}
+ break;
}
_ => {}
}
let binders: Vec<_> = generics
.params
.iter()
- .filter_map(|param| match param.kind {
- GenericParamKind::Lifetime { .. }
- if self.map.late_bound.contains(¶m.hir_id) =>
- {
- Some(param)
- }
- _ => None,
+ .filter(|param| {
+ matches!(param.kind, GenericParamKind::Lifetime { .. })
+ && self.map.late_bound.contains(¶m.hir_id)
})
.enumerate()
.map(|(late_bound_idx, param)| {
let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param);
- let r = late_region_as_bound_region(self.tcx, &pair.1);
- r
+ late_region_as_bound_region(self.tcx, &pair.1)
})
.collect();
self.map.late_bound_vars.insert(hir_id, binders);
#![feature(nll)]
#![recursion_limit = "256"]
#![allow(rustdoc::private_intra_doc_links)]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
impl AmbiguityKind {
fn descr(self) -> &'static str {
match self {
- AmbiguityKind::Import => "name vs any other name during import resolution",
- AmbiguityKind::BuiltinAttr => "built-in attribute vs any other name",
- AmbiguityKind::DeriveHelper => "derive helper attribute vs any other name",
+ AmbiguityKind::Import => "multiple potential import sources",
+ AmbiguityKind::BuiltinAttr => "a name conflict with a builtin attribute",
+ AmbiguityKind::DeriveHelper => "a name conflict with a derive helper attribute",
AmbiguityKind::MacroRulesVsModularized => {
- "`macro_rules` vs non-`macro_rules` from other module"
+ "a conflict between a `macro_rules` name and a non-`macro_rules` name from another module"
}
AmbiguityKind::GlobVsOuter => {
- "glob import vs any other name from outer scope during import/macro resolution"
+ "a conflict between a name from a glob import and an outer scope during import or macro resolution"
}
- AmbiguityKind::GlobVsGlob => "glob import vs glob import in the same module",
+ AmbiguityKind::GlobVsGlob => "multiple glob imports of a name in the same module",
AmbiguityKind::GlobVsExpanded => {
- "glob import vs macro-expanded name in the same \
- module during import/macro resolution"
+ "a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution"
}
AmbiguityKind::MoreExpandedVsOuter => {
- "macro-expanded name vs less macro-expanded name \
- from outer scope during import/macro resolution"
+ "a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution"
}
}
}
} else {
(
format!("use of undeclared crate or module `{}`", ident),
- self.find_similarly_named_module_or_crate(
- ident.name,
- &parent_scope.module,
- )
- .map(|sugg| {
- (
- vec![(ident.span, sugg.to_string())],
+ if ident.name == sym::alloc {
+ Some((
+ vec![],
String::from(
- "there is a crate or module with a similar name",
+ "add `extern crate alloc` to use the `alloc` crate",
),
Applicability::MaybeIncorrect,
+ ))
+ } else {
+ self.find_similarly_named_module_or_crate(
+ ident.name,
+ &parent_scope.module,
)
- }),
+ .map(|sugg| {
+ (
+ vec![(ident.span, sugg.to_string())],
+ String::from(
+ "there is a crate or module with a similar name",
+ ),
+ Applicability::MaybeIncorrect,
+ )
+ })
+ },
)
}
} else {
id,
span,
name: ident.to_string(),
- qualname: format!("{}::{}", qualname, ident.to_string()),
+ qualname: format!("{}::{}", qualname, ident),
value: typ,
parent: None,
children: vec![],
// Rust uses the id of the pattern for var lookups, so we'll use it too.
if !self.span.filter_generated(ident.span) {
- let qualname = format!("{}${}", ident.to_string(), hir_id);
+ let qualname = format!("{}${}", ident, hir_id);
let id = id_from_hir_id(hir_id, &self.save_ctxt);
let span = self.span_from_span(ident.span);
#![feature(if_let_guard)]
#![feature(nll)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
mod dump_visitor;
mod dumper;
| HirDefKind::ForeignMod
| HirDefKind::LifetimeParam
| HirDefKind::AnonConst
+ | HirDefKind::InlineConst
| HirDefKind::Use
| HirDefKind::Field
| HirDefKind::GlobalAsm
pub(super) fn build_target_config(
opts: &Options,
target_override: Option<Target>,
- sysroot: &PathBuf,
+ sysroot: &Path,
) -> Target {
let target_result = target_override.map_or_else(
|| Target::search(&opts.target_triple, sysroot),
#![feature(min_specialization)]
#![feature(once_cell)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
pub const parse_panic_strategy: &str = "either `unwind` or `abort`";
pub const parse_opt_panic_strategy: &str = parse_panic_strategy;
pub const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
- pub const parse_sanitizers: &str =
- "comma separated list of sanitizers: `address`, `hwaddress`, `leak`, `memory` or `thread`";
+ pub const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `hwaddress`, `leak`, `memory` or `thread`";
pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
pub const parse_cfguard: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
for s in v.split(',') {
*slot |= match s {
"address" => SanitizerSet::ADDRESS,
+ "cfi" => SanitizerSet::CFI,
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"thread" => SanitizerSet::THREAD,
match v {
Some(s) => {
if !slot.is_empty() {
- slot.push_str(",");
+ slot.push(',');
}
slot.push_str(s);
true
move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
"the size at which the `large_assignments` lint starts to be emitted"),
mutable_noalias: Option<bool> = (None, parse_opt_bool, [TRACKED],
- "emit noalias metadata for mutable references (default: yes for LLVM >= 12, otherwise no)"),
+ "emit noalias metadata for mutable references (default: yes)"),
new_llvm_pass_manager: Option<bool> = (None, parse_opt_bool, [TRACKED],
"use new LLVM pass manager (default: no)"),
nll_facts: bool = (false, parse_bool, [UNTRACKED],
"compile without linking"),
no_parallel_llvm: bool = (false, parse_no_flag, [UNTRACKED],
"run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
+ no_unique_section_names: bool = (false, parse_bool, [TRACKED],
+ "do not use unique names for text and data sections when -Z function-sections is used"),
no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
"prevent automatic injection of the profiler_builtins crate"),
normalize_docs: bool = (false, parse_bool, [TRACKED],
self.diagnostic().abort_if_errors();
}
pub fn compile_status(&self) -> Result<(), ErrorReported> {
- if self.has_errors() {
+ if self.diagnostic().has_errors_or_lint_errors() {
self.diagnostic().emit_stashed_diagnostics();
Err(ErrorReported)
} else {
pub fn is_nightly_build(&self) -> bool {
self.opts.unstable_features.is_nightly_build()
}
+ pub fn is_sanitizer_cfi_enabled(&self) -> bool {
+ self.opts.debugging_opts.sanitizer.contains(SanitizerSet::CFI)
+ }
pub fn overflow_checks(&self) -> bool {
self.opts
.cg
disable it using `-C target-feature=-crt-static`",
);
}
+
+ // LLVM CFI requires LTO.
+ if sess.is_sanitizer_cfi_enabled() {
+ if sess.opts.cg.lto == config::LtoCli::Unspecified
+ || sess.opts.cg.lto == config::LtoCli::No
+ || sess.opts.cg.lto == config::LtoCli::Thin
+ {
+ sess.err("`-Zsanitizer=cfi` requires `-Clto`");
+ }
+ }
}
/// Holds data on the current incremental compilation session, if there is one.
/// pub fn f() {} // `f`'s `SyntaxContext` has a single `ExpnId` from `m`.
/// pub fn $i() {} // `$i`'s `SyntaxContext` is empty.
/// }
- /// n(f);
+ /// n!(f);
/// macro n($j:ident) {
/// use foo::*;
/// f(); // `f`'s `SyntaxContext` has a mark from `m` and a mark from `n`
#![feature(nll)]
#![feature(min_specialization)]
#![feature(thread_local_const_init)]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
encoder.emit_enum(|encoder| match *self {
RealFileName::LocalPath(ref local_path) => {
encoder.emit_enum_variant("LocalPath", 0, 1, |encoder| {
- Ok({
- encoder
- .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
- })
+ encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
+ Ok(())
})
}
// For privacy and build reproducibility, we must not embed host-dependant path in artifacts
// if they have been remapped by --remap-path-prefix
assert!(local_path.is_none());
- Ok({
- encoder
- .emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
- encoder
- .emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
- })
+ encoder.emit_enum_variant_arg(true, |encoder| local_path.encode(encoder))?;
+ encoder.emit_enum_variant_arg(false, |encoder| virtual_name.encode(encoder))?;
+ Ok(())
}),
})
}
__S,
__next,
__try_var,
+ _args,
_d,
_e,
_task_context,
as_ptr,
as_str,
asm,
+ asm_const,
+ asm_experimental_arch,
+ asm_sym,
assert,
assert_inhabited,
assert_macro,
cfg_target_thread_local,
cfg_target_vendor,
cfg_version,
+ cfi,
char,
client,
clippy,
div_assign,
doc,
doc_alias,
+ doc_auto_cfg,
doc_cfg,
doc_cfg_hide,
doc_keyword,
rustc_layout_scalar_valid_range_end,
rustc_layout_scalar_valid_range_start,
rustc_legacy_const_generics,
- rustc_lint_query_instability,
rustc_macro_transparency,
rustc_main,
rustc_mir,
rustc_partition_reused,
rustc_peek,
rustc_peek_definite_init,
- rustc_peek_indirectly_mutable,
rustc_peek_liveness,
rustc_peek_maybe_init,
rustc_peek_maybe_uninit,
#![feature(in_band_lifetimes)]
#![feature(iter_zip)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_middle;
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Instance, TyCtxt};
+use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_session::config::SymbolManglingVersion;
+use rustc_target::abi::call::FnAbi;
use tracing::debug;
ty::SymbolName::new(tcx, &symbol_name)
}
+/// This function computes the typeid for the given function ABI.
+pub fn typeid_for_fnabi(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
+ v0::mangle_typeid_for_fnabi(tcx, fn_abi)
+}
+
/// Computes the symbol name for the given instance. This function will call
/// `compute_instantiating_crate` if it needs to factor the instantiating crate
/// into the symbol name.
use rustc_middle::ty::print::{Print, Printer};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
use rustc_middle::ty::{self, FloatTy, Instance, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
+use rustc_target::abi::call::FnAbi;
use rustc_target::abi::Integer;
use rustc_target::spec::abi::Abi;
std::mem::take(&mut cx.out)
}
+pub(super) fn mangle_typeid_for_fnabi(
+ _tcx: TyCtxt<'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+) -> String {
+ // LLVM uses type metadata to allow IR modules to aggregate pointers by their types.[1] This
+ // type metadata is used by LLVM Control Flow Integrity to test whether a given pointer is
+ // associated with a type identifier (i.e., test type membership).
+ //
+ // Clang uses the Itanium C++ ABI's[2] virtual tables and RTTI typeinfo structure name[3] as
+ // type metadata identifiers for function pointers. The typeinfo name encoding is a
+ // two-character code (i.e., “TS”) prefixed to the type encoding for the function.
+ //
+ // For cross-language LLVM CFI support, a compatible encoding must be used by either
+ //
+ // a. Using a superset of types that encompasses types used by Clang (i.e., Itanium C++ ABI's
+ // type encodings[4]), or at least types used at the FFI boundary.
+ // b. Reducing the types to the least common denominator between types used by Clang (or at
+ // least types used at the FFI boundary) and Rust compilers (if even possible).
+ // c. Creating a new ABI for cross-language CFI and using it for Clang and Rust compilers (and
+ // possibly other compilers).
+ //
+ // Option (b) may weaken the protection for Rust-compiled only code, so it should be provided
+ // as an alternative to a Rust-specific encoding for when mixing Rust and C and C++ -compiled
+ // code. Option (c) would require changes to Clang to use the new ABI.
+ //
+ // [1] https://llvm.org/docs/TypeMetadata.html
+ // [2] https://itanium-cxx-abi.github.io/cxx-abi/abi.html
+ // [3] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-special-vtables
+ // [4] https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-type
+ //
+ // FIXME(rcvalle): See comment above.
+ let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize;
+ format!("typeid{}", arg_count)
+}
+
struct BinderLevel {
/// The range of distances from the root of what's
/// being printed, to the lifetimes in a binder.
const NonNull = 1 << 3;
const ReadOnly = 1 << 4;
const InReg = 1 << 5;
- // NoAlias on &mut arguments can only be used with LLVM >= 12 due to miscompiles
- // in earlier versions. FIXME: Remove this distinction once possible.
+ // Due to past miscompiles in LLVM, we use a separate attribute for
+ // &mut arguments, so that the codegen backend can decide whether
+ // or not to actually emit the attribute. It can also be controlled
+ // with the `-Zmutable-noalias` debugging option.
const NoAliasMutRef = 1 << 6;
}
}
pub fn target() -> Target {
let mut base = super::apple_base::opts("macos");
- base.cpu = "apple-a12".to_string();
+ base.cpu = "apple-a14".to_string();
base.max_atomic_width = Some(128);
// FIXME: The leak sanitizer currently fails the tests, see #88132.
- base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-arch".to_string(), "arm64".to_string()]);
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
options: TargetOptions {
+ features: "+outline-atomics".to_string(),
max_atomic_width: Some(128),
mcount: "\u{1}_mcount".to_string(),
endian: Endian::Big,
arch: "aarch64".to_string(),
options: TargetOptions {
abi: "ilp32".to_string(),
+ features: "+outline-atomics".to_string(),
mcount: "\u{1}_mcount".to_string(),
endian: Endian::Big,
..base
arch: "aarch64".to_string(),
options: TargetOptions {
max_atomic_width: Some(128),
- supported_sanitizers: SanitizerSet::ADDRESS,
+ supported_sanitizers: SanitizerSet::ADDRESS | SanitizerSet::CFI,
..super::fuchsia_base::opts()
},
}
// As documented in https://developer.android.com/ndk/guides/cpu-features.html
// the neon (ASIMD) and FP must exist on all android aarch64 targets.
features: "+neon,+fp-armv8".to_string(),
- supported_sanitizers: SanitizerSet::HWADDRESS,
+ supported_sanitizers: SanitizerSet::CFI | SanitizerSet::HWADDRESS,
..super::android_base::opts()
},
}
options: TargetOptions {
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
| SanitizerSet::MEMORY
| SanitizerSet::THREAD,
..super::freebsd_base::opts()
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
options: TargetOptions {
+ features: "+outline-atomics".to_string(),
mcount: "\u{1}_mcount".to_string(),
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
| SanitizerSet::LEAK
| SanitizerSet::MEMORY
| SanitizerSet::THREAD
arch: "aarch64".to_string(),
options: TargetOptions {
abi: "ilp32".to_string(),
+ features: "+outline-atomics".to_string(),
max_atomic_width: Some(128),
mcount: "\u{1}_mcount".to_string(),
..super::linux_gnu_base::opts()
pointer_width: 64,
data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
arch: "aarch64".to_string(),
- options: TargetOptions { mcount: "\u{1}_mcount".to_string(), ..base },
+ options: TargetOptions {
+ features: "+outline-atomics".to_string(),
+ mcount: "\u{1}_mcount".to_string(),
+ ..base
+ },
}
}
-use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, RelocModel, Target, TargetOptions};
+use crate::spec::{LinkArgs, LinkerFlavor, RelocModel, Target, TargetOptions};
/// A base target for Nintendo 3DS devices using the devkitARM toolchain.
///
features: "+vfp2".to_string(),
pre_link_args,
exe_suffix: ".elf".to_string(),
- panic_strategy: PanicStrategy::Abort,
..Default::default()
},
}
);
TargetOptions {
- os: "hermit".to_string(),
linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
disable_redzone: true,
linker: Some("rust-lld".to_owned()),
const MEMORY = 1 << 2;
const THREAD = 1 << 3;
const HWADDRESS = 1 << 4;
+ const CFI = 1 << 5;
}
}
fn as_str(self) -> Option<&'static str> {
Some(match self {
SanitizerSet::ADDRESS => "address",
+ SanitizerSet::CFI => "cfi",
SanitizerSet::LEAK => "leak",
SanitizerSet::MEMORY => "memory",
SanitizerSet::THREAD => "thread",
fn into_iter(self) -> Self::IntoIter {
[
SanitizerSet::ADDRESS,
+ SanitizerSet::CFI,
SanitizerSet::LEAK,
SanitizerSet::MEMORY,
SanitizerSet::THREAD,
("armv6k-nintendo-3ds", armv6k_nintendo_3ds),
("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
+
+ ("x86_64-unknown-none", x86_64_unknown_none),
}
/// Warnings encountered when parsing the target `json`.
AmdGpuKernel => self.arch == "amdgcn",
AvrInterrupt | AvrNonBlockingInterrupt => self.arch == "avr",
Wasm => ["wasm32", "wasm64"].contains(&&self.arch[..]),
+ Thiscall { .. } => self.arch == "x86",
// On windows these fall-back to platform native calling convention (C) when the
// architecture is not supported.
//
// > convention is used.
//
// -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
- Stdcall { .. } | Fastcall | Thiscall { .. } | Vectorcall if self.is_like_windows => {
- true
- }
+ Stdcall { .. } | Fastcall | Vectorcall if self.is_like_windows => true,
// Outside of Windows we want to only support these calling conventions for the
// architectures for which these calling conventions are actually well defined.
- Stdcall { .. } | Fastcall | Thiscall { .. } if self.arch == "x86" => true,
+ Stdcall { .. } | Fastcall if self.arch == "x86" => true,
Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
// Return a `None` for other cases so that we know to emit a future compat lint.
- Stdcall { .. } | Fastcall | Thiscall { .. } | Vectorcall => return None,
+ Stdcall { .. } | Fastcall | Vectorcall => return None,
})
}
for s in a {
base.$key_name |= match s.as_string() {
Some("address") => SanitizerSet::ADDRESS,
+ Some("cfi") => SanitizerSet::CFI,
Some("leak") => SanitizerSet::LEAK,
Some("memory") => SanitizerSet::MEMORY,
Some("thread") => SanitizerSet::THREAD,
/// JSON decoding.
pub fn search(
target_triple: &TargetTriple,
- sysroot: &PathBuf,
+ sysroot: &Path,
) -> Result<(Target, TargetWarnings), String> {
use rustc_serialize::json;
use std::env;
base.link_env_remove.extend(super::apple_base::macos_link_env_remove());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
+ base.supported_sanitizers =
+ SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD;
// Clang automatically chooses a more specific target based on
// MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work
base.max_atomic_width = Some(64);
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
Target {
llvm_target: "x86_64-fuchsia".to_string(),
base.max_atomic_width = Some(64);
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
Target {
llvm_target: "x86_64-pc-solaris".to_string(),
base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers =
+ SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::MEMORY | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-freebsd".to_string(),
base.pre_link_args.insert(LinkerFlavor::Gcc, vec!["-m64".to_string(), "-std=c99".to_string()]);
base.cpu = "x86-64".to_string();
base.max_atomic_width = Some(64);
- base.supported_sanitizers = SanitizerSet::ADDRESS;
+ base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI;
Target {
// LLVM does not currently have a separate illumos target,
base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers =
- SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-linux-gnu".to_string(),
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
base.static_position_independent_executables = true;
- base.supported_sanitizers =
- SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-linux-musl".to_string(),
base.pre_link_args.entry(LinkerFlavor::Gcc).or_default().push("-m64".to_string());
// don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
base.stack_probes = StackProbeType::Call;
- base.supported_sanitizers =
- SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD;
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD;
Target {
llvm_target: "x86_64-unknown-netbsd".to_string(),
--- /dev/null
+// Generic x86-64 target for bare-metal code - Floating point disabled
+//
+// Can be used in conjunction with the `target-feature` and
+// `target-cpu` compiler flags to opt-in more hardware-specific
+// features.
+
+use super::{
+ CodeModel, LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, RelroLevel, StackProbeType,
+ Target, TargetOptions,
+};
+
+pub fn target() -> Target {
+ let opts = TargetOptions {
+ cpu: "x86-64".to_string(),
+ max_atomic_width: Some(64),
+ // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
+ stack_probes: StackProbeType::Call,
+ position_independent_executables: true,
+ static_position_independent_executables: true,
+ relro_level: RelroLevel::Full,
+ relocation_model: RelocModel::Pic,
+ linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
+ linker: Some("rust-lld".to_owned()),
+ features:
+ "-mmx,-sse,-sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-3dnow,-3dnowa,-avx,-avx2,+soft-float"
+ .to_string(),
+ executables: true,
+ disable_redzone: true,
+ panic_strategy: PanicStrategy::Abort,
+ code_model: Some(CodeModel::Kernel),
+ ..Default::default()
+ };
+ Target {
+ llvm_target: "x86_64-unknown-none-elf".to_string(),
+ pointer_width: 64,
+ data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+ .to_string(),
+ arch: "x86_64".to_string(),
+ options: opts,
+ }
+}
},
cause,
);
- if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
+ let errors = fulfillcx.select_where_possible(&self.infcx);
+ if !errors.is_empty() {
// This shouldn't happen, except for evaluate/fulfill mismatches,
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
// by design).
- debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
+ debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors);
return None;
}
let obligations = fulfillcx.pending_obligations();
#![feature(crate_visibility_modifier)]
#![feature(control_flow_enum)]
#![recursion_limit = "512"] // For rustdoc
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate rustc_macros;
-use crate::traits::{self, ObligationCause, PredicateObligation};
+use crate::traits;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
-use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
-use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
-use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{InferCtxt, InferOk};
-use rustc_middle::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst};
+use rustc_infer::infer::InferCtxt;
+use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, InternalSubsts};
use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt};
use rustc_span::Span;
-use std::ops::ControlFlow;
-
pub trait InferCtxtExt<'tcx> {
- fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
- &self,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- value: T,
- value_span: Span,
- ) -> InferOk<'tcx, T>;
-
- fn constrain_opaque_types(&self);
-
- fn constrain_opaque_type(
- &self,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- );
-
- /*private*/
- fn generate_member_constraint(
- &self,
- concrete_ty: Ty<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- first_own_region_index: usize,
- );
-
fn infer_opaque_definition_from_instantiation(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
}
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
- /// Replaces all opaque types in `value` with fresh inference variables
- /// and creates appropriate obligations. For example, given the input:
- ///
- /// impl Iterator<Item = impl Debug>
- ///
- /// this method would create two type variables, `?0` and `?1`. It would
- /// return the type `?0` but also the obligations:
- ///
- /// ?0: Iterator<Item = ?1>
- /// ?1: Debug
- ///
- /// Moreover, it returns an `OpaqueTypeMap` that would map `?0` to
- /// info about the `impl Iterator<..>` type and `?1` to info about
- /// the `impl Debug` type.
- ///
- /// # Parameters
- ///
- /// - `parent_def_id` -- the `DefId` of the function in which the opaque type
- /// is defined
- /// - `body_id` -- the body-id with which the resulting obligations should
- /// be associated
- /// - `param_env` -- the in-scope parameter environment to be used for
- /// obligations
- /// - `value` -- the value within which we are instantiating opaque types
- /// - `value_span` -- the span where the value came from, used in error reporting
- fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
- &self,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- value: T,
- value_span: Span,
- ) -> InferOk<'tcx, T> {
- debug!(
- "instantiate_opaque_types(value={:?}, body_id={:?}, \
- param_env={:?}, value_span={:?})",
- value, body_id, param_env, value_span,
- );
- let mut instantiator =
- Instantiator { infcx: self, body_id, param_env, value_span, obligations: vec![] };
- let value = instantiator.instantiate_opaque_types_in_map(value);
- InferOk { value, obligations: instantiator.obligations }
- }
-
- /// Given the map `opaque_types` containing the opaque
- /// `impl Trait` types whose underlying, hidden types are being
- /// inferred, this method adds constraints to the regions
- /// appearing in those underlying hidden types to ensure that they
- /// at least do not refer to random scopes within the current
- /// function. These constraints are not (quite) sufficient to
- /// guarantee that the regions are actually legal values; that
- /// final condition is imposed after region inference is done.
- ///
- /// # The Problem
- ///
- /// Let's work through an example to explain how it works. Assume
- /// the current function is as follows:
- ///
- /// ```text
- /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>)
- /// ```
- ///
- /// Here, we have two `impl Trait` types whose values are being
- /// inferred (the `impl Bar<'a>` and the `impl
- /// Bar<'b>`). Conceptually, this is sugar for a setup where we
- /// define underlying opaque types (`Foo1`, `Foo2`) and then, in
- /// the return type of `foo`, we *reference* those definitions:
- ///
- /// ```text
- /// type Foo1<'x> = impl Bar<'x>;
- /// type Foo2<'x> = impl Bar<'x>;
- /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. }
- /// // ^^^^ ^^
- /// // | |
- /// // | substs
- /// // def_id
- /// ```
- ///
- /// As indicating in the comments above, each of those references
- /// is (in the compiler) basically a substitution (`substs`)
- /// applied to the type of a suitable `def_id` (which identifies
- /// `Foo1` or `Foo2`).
- ///
- /// Now, at this point in compilation, what we have done is to
- /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with
- /// fresh inference variables C1 and C2. We wish to use the values
- /// of these variables to infer the underlying types of `Foo1` and
- /// `Foo2`. That is, this gives rise to higher-order (pattern) unification
- /// constraints like:
- ///
- /// ```text
- /// for<'a> (Foo1<'a> = C1)
- /// for<'b> (Foo1<'b> = C2)
- /// ```
- ///
- /// For these equation to be satisfiable, the types `C1` and `C2`
- /// can only refer to a limited set of regions. For example, `C1`
- /// can only refer to `'static` and `'a`, and `C2` can only refer
- /// to `'static` and `'b`. The job of this function is to impose that
- /// constraint.
- ///
- /// Up to this point, C1 and C2 are basically just random type
- /// inference variables, and hence they may contain arbitrary
- /// regions. In fact, it is fairly likely that they do! Consider
- /// this possible definition of `foo`:
- ///
- /// ```text
- /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) {
- /// (&*x, &*y)
- /// }
- /// ```
- ///
- /// Here, the values for the concrete types of the two impl
- /// traits will include inference variables:
- ///
- /// ```text
- /// &'0 i32
- /// &'1 i32
- /// ```
- ///
- /// Ordinarily, the subtyping rules would ensure that these are
- /// sufficiently large. But since `impl Bar<'a>` isn't a specific
- /// type per se, we don't get such constraints by default. This
- /// is where this function comes into play. It adds extra
- /// constraints to ensure that all the regions which appear in the
- /// inferred type are regions that could validly appear.
- ///
- /// This is actually a bit of a tricky constraint in general. We
- /// want to say that each variable (e.g., `'0`) can only take on
- /// values that were supplied as arguments to the opaque type
- /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in
- /// scope. We don't have a constraint quite of this kind in the current
- /// region checker.
- ///
- /// # The Solution
- ///
- /// We generally prefer to make `<=` constraints, since they
- /// integrate best into the region solver. To do that, we find the
- /// "minimum" of all the arguments that appear in the substs: that
- /// is, some region which is less than all the others. In the case
- /// of `Foo1<'a>`, that would be `'a` (it's the only choice, after
- /// all). Then we apply that as a least bound to the variables
- /// (e.g., `'a <= '0`).
- ///
- /// In some cases, there is no minimum. Consider this example:
- ///
- /// ```text
- /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... }
- /// ```
- ///
- /// Here we would report a more complex "in constraint", like `'r
- /// in ['a, 'b, 'static]` (where `'r` is some region appearing in
- /// the hidden type).
- ///
- /// # Constrain regions, not the hidden concrete type
- ///
- /// Note that generating constraints on each region `Rc` is *not*
- /// the same as generating an outlives constraint on `Tc` iself.
- /// For example, if we had a function like this:
- ///
- /// ```rust
- /// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> {
- /// (x, y)
- /// }
- ///
- /// // Equivalent to:
- /// type FooReturn<'a, T> = impl Foo<'a>;
- /// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. }
- /// ```
- ///
- /// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0`
- /// is an inference variable). If we generated a constraint that
- /// `Tc: 'a`, then this would incorrectly require that `T: 'a` --
- /// but this is not necessary, because the opaque type we
- /// create will be allowed to reference `T`. So we only generate a
- /// constraint that `'0: 'a`.
- ///
- /// # The `free_region_relations` parameter
- ///
- /// The `free_region_relations` argument is used to find the
- /// "minimum" of the regions supplied to a given opaque type.
- /// It must be a relation that can answer whether `'a <= 'b`,
- /// where `'a` and `'b` are regions that appear in the "substs"
- /// for the opaque type references (the `<'a>` in `Foo1<'a>`).
- ///
- /// Note that we do not impose the constraints based on the
- /// generic regions from the `Foo1` definition (e.g., `'x`). This
- /// is because the constraints we are imposing here is basically
- /// the concern of the one generating the constraining type C1,
- /// which is the current function. It also means that we can
- /// take "implied bounds" into account in some cases:
- ///
- /// ```text
- /// trait SomeTrait<'a, 'b> { }
- /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. }
- /// ```
- ///
- /// Here, the fact that `'b: 'a` is known only because of the
- /// implied bounds from the `&'a &'b u32` parameter, and is not
- /// "inherent" to the opaque type definition.
- ///
- /// # Parameters
- ///
- /// - `opaque_types` -- the map produced by `instantiate_opaque_types`
- /// - `free_region_relations` -- something that can be used to relate
- /// the free regions (`'a`) that appear in the impl trait.
- fn constrain_opaque_types(&self) {
- let opaque_types = self.inner.borrow().opaque_types.clone();
- for (opaque_type_key, opaque_defn) in opaque_types {
- self.constrain_opaque_type(opaque_type_key, &opaque_defn);
- }
- }
-
- /// See `constrain_opaque_types` for documentation.
- #[instrument(level = "debug", skip(self))]
- fn constrain_opaque_type(
- &self,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- ) {
- let def_id = opaque_type_key.def_id;
-
- let tcx = self.tcx;
-
- let concrete_ty = self.resolve_vars_if_possible(opaque_defn.concrete_ty);
-
- debug!(?concrete_ty);
-
- let first_own_region = match opaque_defn.origin {
- hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
- // We lower
- //
- // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
- //
- // into
- //
- // type foo::<'p0..'pn>::Foo<'q0..'qm>
- // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
- //
- // For these types we only iterate over `'l0..lm` below.
- tcx.generics_of(def_id).parent_count
- }
- // These opaque type inherit all lifetime parameters from their
- // parent, so we have to check them all.
- hir::OpaqueTyOrigin::TyAlias => 0,
- };
-
- // The regions that appear in the hidden type must be equal to
- // one of the regions in scope for the opaque type.
- self.generate_member_constraint(
- concrete_ty,
- opaque_defn,
- opaque_type_key,
- first_own_region,
- );
- }
-
- /// As a fallback, we sometimes generate an "in constraint". For
- /// a case like `impl Foo<'a, 'b>`, where `'a` and `'b` cannot be
- /// related, we would generate a constraint `'r in ['a, 'b,
- /// 'static]` for each region `'r` that appears in the hidden type
- /// (i.e., it must be equal to `'a`, `'b`, or `'static`).
- ///
- /// `conflict1` and `conflict2` are the two region bounds that we
- /// detected which were unrelated. They are used for diagnostics.
- fn generate_member_constraint(
- &self,
- concrete_ty: Ty<'tcx>,
- opaque_defn: &OpaqueTypeDecl<'tcx>,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- first_own_region: usize,
- ) {
- // Create the set of choice regions: each region in the hidden
- // type can be equal to any of the region parameters of the
- // opaque type definition.
- let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new(
- opaque_type_key.substs[first_own_region..]
- .iter()
- .filter_map(|arg| match arg.unpack() {
- GenericArgKind::Lifetime(r) => Some(r),
- GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
- })
- .chain(std::iter::once(self.tcx.lifetimes.re_static))
- .collect(),
- );
-
- concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
- tcx: self.tcx,
- op: |r| {
- self.member_constraint(
- opaque_type_key.def_id,
- opaque_defn.definition_span,
- concrete_ty,
- r,
- &choice_regions,
- )
- },
- });
- }
-
/// Given the fully resolved, instantiated type for an opaque
/// type, i.e., the value of an inference variable like C1 or C2
/// (*), computes the "definition type" for an opaque type
/// purpose of this function is to do that translation.
///
/// (*) C1 and C2 were introduced in the comments on
- /// `constrain_opaque_types`. Read that comment for more context.
+ /// `constrain_opaque_type`. Read that comment for more context.
///
/// # Parameters
///
}
}
-// Visitor that requires that (almost) all regions in the type visited outlive
-// `least_region`. We cannot use `push_outlives_components` because regions in
-// closure signatures are not included in their outlives components. We need to
-// ensure all regions outlive the given bound so that we don't end up with,
-// say, `ReVar` appearing in a return type and causing ICEs when other
-// functions end up with region constraints involving regions from other
-// functions.
-//
-// We also cannot use `for_each_free_region` because for closures it includes
-// the regions parameters from the enclosing item.
-//
-// We ignore any type parameters because impl trait values are assumed to
-// capture all the in-scope type parameters.
-struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> {
- tcx: TyCtxt<'tcx>,
- op: OP,
-}
-
-impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
-where
- OP: FnMut(ty::Region<'tcx>),
-{
- fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
- Some(self.tcx)
- }
-
- fn visit_binder<T: TypeFoldable<'tcx>>(
- &mut self,
- t: &ty::Binder<'tcx, T>,
- ) -> ControlFlow<Self::BreakTy> {
- t.as_ref().skip_binder().visit_with(self);
- ControlFlow::CONTINUE
- }
-
- fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- match *r {
- // ignore bound regions, keep visiting
- ty::ReLateBound(_, _) => ControlFlow::CONTINUE,
- _ => {
- (self.op)(r);
- ControlFlow::CONTINUE
- }
- }
- }
-
- fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- // We're only interested in types involving regions
- if !ty.flags().intersects(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
- return ControlFlow::CONTINUE;
- }
-
- match ty.kind() {
- ty::Closure(_, ref substs) => {
- // Skip lifetime parameters of the enclosing item(s)
-
- substs.as_closure().tupled_upvars_ty().visit_with(self);
- substs.as_closure().sig_as_fn_ptr_ty().visit_with(self);
- }
-
- ty::Generator(_, ref substs, _) => {
- // Skip lifetime parameters of the enclosing item(s)
- // Also skip the witness type, because that has no free regions.
-
- substs.as_generator().tupled_upvars_ty().visit_with(self);
- substs.as_generator().return_ty().visit_with(self);
- substs.as_generator().yield_ty().visit_with(self);
- substs.as_generator().resume_ty().visit_with(self);
- }
- _ => {
- ty.super_visit_with(self);
- }
- }
-
- ControlFlow::CONTINUE
- }
-}
-
struct ReverseMapper<'tcx> {
tcx: TyCtxt<'tcx>,
}
}
-struct Instantiator<'a, 'tcx> {
- infcx: &'a InferCtxt<'a, 'tcx>,
- body_id: hir::HirId,
- param_env: ty::ParamEnv<'tcx>,
- value_span: Span,
- obligations: Vec<PredicateObligation<'tcx>>,
-}
-
-impl<'a, 'tcx> Instantiator<'a, 'tcx> {
- fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
- let tcx = self.infcx.tcx;
- value.fold_with(&mut BottomUpFolder {
- tcx,
- ty_op: |ty| {
- if ty.references_error() {
- return tcx.ty_error();
- } else if let ty::Opaque(def_id, substs) = ty.kind() {
- // Check that this is `impl Trait` type is
- // declared by `parent_def_id` -- i.e., one whose
- // value we are inferring. At present, this is
- // always true during the first phase of
- // type-check, but not always true later on during
- // NLL. Once we support named opaque types more fully,
- // this same scenario will be able to arise during all phases.
- //
- // Here is an example using type alias `impl Trait`
- // that indicates the distinction we are checking for:
- //
- // ```rust
- // mod a {
- // pub type Foo = impl Iterator;
- // pub fn make_foo() -> Foo { .. }
- // }
- //
- // mod b {
- // fn foo() -> a::Foo { a::make_foo() }
- // }
- // ```
- //
- // Here, the return type of `foo` references an
- // `Opaque` indeed, but not one whose value is
- // presently being inferred. You can get into a
- // similar situation with closure return types
- // today:
- //
- // ```rust
- // fn foo() -> impl Iterator { .. }
- // fn bar() {
- // let x = || foo(); // returns the Opaque assoc with `foo`
- // }
- // ```
- if let Some(def_id) = def_id.as_local() {
- let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let parent_def_id = self.infcx.defining_use_anchor;
- let def_scope_default = || {
- let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id);
- parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id)
- };
- let (in_definition_scope, origin) =
- match tcx.hir().expect_item(opaque_hir_id).kind {
- // Anonymous `impl Trait`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: Some(parent),
- origin,
- ..
- }) => (parent == parent_def_id.to_def_id(), origin),
- // Named `type Foo = impl Bar;`
- hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- impl_trait_fn: None,
- origin,
- ..
- }) => (
- may_define_opaque_type(tcx, parent_def_id, opaque_hir_id),
- origin,
- ),
- _ => (def_scope_default(), hir::OpaqueTyOrigin::TyAlias),
- };
- if in_definition_scope {
- let opaque_type_key =
- OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
- return self.fold_opaque_ty(ty, opaque_type_key, origin);
- }
-
- debug!(
- "instantiate_opaque_types_in_map: \
- encountered opaque outside its definition scope \
- def_id={:?}",
- def_id,
- );
- }
- }
-
- ty
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- })
- }
-
- #[instrument(skip(self), level = "debug")]
- fn fold_opaque_ty(
- &mut self,
- ty: Ty<'tcx>,
- opaque_type_key: OpaqueTypeKey<'tcx>,
- origin: hir::OpaqueTyOrigin,
- ) -> Ty<'tcx> {
- let infcx = self.infcx;
- let tcx = infcx.tcx;
- let OpaqueTypeKey { def_id, substs } = opaque_type_key;
-
- // Use the same type variable if the exact same opaque type appears more
- // than once in the return type (e.g., if it's passed to a type alias).
- if let Some(opaque_defn) = infcx.inner.borrow().opaque_types.get(&opaque_type_key) {
- debug!("re-using cached concrete type {:?}", opaque_defn.concrete_ty.kind());
- return opaque_defn.concrete_ty;
- }
-
- let ty_var = infcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
- span: self.value_span,
- });
-
- // Ideally, we'd get the span where *this specific `ty` came
- // from*, but right now we just use the span from the overall
- // value being folded. In simple cases like `-> impl Foo`,
- // these are the same span, but not in cases like `-> (impl
- // Foo, impl Bar)`.
- let definition_span = self.value_span;
-
- {
- let mut infcx = self.infcx.inner.borrow_mut();
- infcx.opaque_types.insert(
- OpaqueTypeKey { def_id, substs },
- OpaqueTypeDecl { opaque_type: ty, definition_span, concrete_ty: ty_var, origin },
- );
- infcx.opaque_types_vars.insert(ty_var, ty);
- }
-
- debug!("generated new type inference var {:?}", ty_var.kind());
-
- let item_bounds = tcx.explicit_item_bounds(def_id);
-
- self.obligations.reserve(item_bounds.len());
- for (predicate, _) in item_bounds {
- debug!(?predicate);
- let predicate = predicate.subst(tcx, substs);
- debug!(?predicate);
-
- // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
- let predicate = predicate.fold_with(&mut BottomUpFolder {
- tcx,
- ty_op: |ty| match ty.kind() {
- ty::Projection(projection_ty) => infcx.infer_projection(
- self.param_env,
- *projection_ty,
- ObligationCause::misc(self.value_span, self.body_id),
- 0,
- &mut self.obligations,
- ),
- _ => ty,
- },
- lt_op: |lt| lt,
- ct_op: |ct| ct,
- });
- debug!(?predicate);
-
- if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
- if projection.ty.references_error() {
- // No point on adding these obligations since there's a type error involved.
- return tcx.ty_error();
- }
- }
- // Change the predicate to refer to the type variable,
- // which will be the concrete type instead of the opaque type.
- // This also instantiates nested instances of `impl Trait`.
- let predicate = self.instantiate_opaque_types_in_map(predicate);
-
- let cause =
- traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
-
- // Require that the predicate holds for the concrete type.
- debug!(?predicate);
- self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate));
- }
-
- ty_var
- }
-}
-
-/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`.
-///
-/// Example:
-/// ```rust
-/// pub mod foo {
-/// pub mod bar {
-/// pub trait Bar { .. }
-///
-/// pub type Baz = impl Bar;
-///
-/// fn f1() -> Baz { .. }
-/// }
-///
-/// fn f2() -> bar::Baz { .. }
-/// }
-/// ```
-///
-/// Here, `def_id` is the `LocalDefId` of the defining use of the opaque type (e.g., `f1` or `f2`),
-/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`.
-/// For the above example, this function returns `true` for `f1` and `false` for `f2`.
-fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool {
- let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
- // Named opaque types can be defined by any siblings or children of siblings.
- let scope = tcx.hir().get_defining_scope(opaque_hir_id);
- // We walk up the node tree until we hit the root or the scope of the opaque type.
- while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
- hir_id = tcx.hir().get_parent_item(hir_id);
- }
- // Syntactically, we are allowed to define the concrete type if:
- let res = hir_id == scope;
- trace!(
- "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}",
- tcx.hir().find(hir_id),
- tcx.hir().get(opaque_hir_id),
- res
- );
- res
-}
-
/// Given a set of predicates that apply to an object type, returns
/// the region bounds that the (erased) `Self` type must
/// outlive. Precisely *because* the `Self` type is erased, the
// an additional sanity check.
let mut fulfill = FulfillmentContext::new();
fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
- fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| {
- panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, e)
- });
+ let errors = fulfill.select_all_or_error(&infcx);
+
+ if !errors.is_empty() {
+ panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
+ }
let body_id_map: FxHashMap<_, _> = infcx
.inner
self.obligations.insert(obligation);
}
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_where_possible(infcx)?;
-
- if self.obligations.is_empty() {
- Ok(())
- } else {
- let errors = self
- .obligations
- .iter()
- .map(|obligation| FulfillmentError {
- obligation: obligation.clone(),
- code: FulfillmentErrorCode::CodeAmbiguity,
- // FIXME - does Chalk have a notation of 'root obligation'?
- // This is just for diagnostics, so it's okay if this is wrong
- root_obligation: obligation.clone(),
- })
- .collect();
- Err(errors)
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_where_possible(infcx);
+
+ if !errors.is_empty() {
+ return errors;
+ }
}
+
+ // any remaining obligations are errors
+ self.obligations
+ .iter()
+ .map(|obligation| FulfillmentError {
+ obligation: obligation.clone(),
+ code: FulfillmentErrorCode::CodeAmbiguity,
+ // FIXME - does Chalk have a notation of 'root obligation'?
+ // This is just for diagnostics, so it's okay if this is wrong
+ root_obligation: obligation.clone(),
+ })
+ .collect()
}
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
assert!(!infcx.is_in_snapshot());
let mut errors = Vec::new();
}
}
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ errors
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
- if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
&format!("Encountered errors `{:?}` resolving bounds after type-checking", errors),
if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
match infcx.tcx.def_kind(uv.def.did) {
- DefKind::AnonConst => {
+ DefKind::AnonConst | DefKind::InlineConst => {
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
if mir_body.is_polymorphic {
// we want to look into them or treat them as opaque projections.
//
// Right now we do neither of that and simply always fail to unify them.
- DefKind::AnonConst => (),
+ DefKind::AnonConst | DefKind::InlineConst => (),
_ => return Ok(None),
}
}
}
}
+ ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+ self.get_parent_trait_ref(&parent_code)
+ }
_ => None,
}
}
post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"),
post.len() - 4,
)
- } else if post.len() > 1 || (post.len() == 1 && post[0].contains("\n")) {
+ } else if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
} else if post.len() == 1 {
format!(": `{}`", post[0])
let sized_trait = self.tcx.lang_items().sized_trait();
debug!("maybe_suggest_unsized_generics: generics.params={:?}", generics.params);
debug!("maybe_suggest_unsized_generics: generics.where_clause={:?}", generics.where_clause);
- let param = generics
- .params
- .iter()
- .filter(|param| param.span == span)
- .filter(|param| {
- // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
- // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
- param
- .bounds
- .iter()
- .all(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) != sized_trait)
- })
- .next();
+ let param = generics.params.iter().filter(|param| param.span == span).find(|param| {
+ // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
+ // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
+ param
+ .bounds
+ .iter()
+ .all(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) != sized_trait)
+ });
let param = match param {
Some(param) => param,
_ => return,
outer_generator: Option<DefId>,
trait_ref: ty::TraitRef<'tcx>,
target_ty: Ty<'tcx>,
- typeck_results: &ty::TypeckResults<'tcx>,
+ typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>,
);
while let Some(code) = next_code {
debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code);
match code {
+ ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+ next_code = Some(parent_code.as_ref());
+ }
ObligationCauseCode::DerivedObligation(derived_obligation)
| ObligationCauseCode::BuiltinDerivedObligation(derived_obligation)
| ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
}
// Only continue if a generator was found.
- debug!(
- "maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \
- target_ty={:?}",
- generator, trait_ref, target_ty
- );
+ debug!(?generator, ?trait_ref, ?target_ty, "maybe_note_obligation_cause_for_async_await");
let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) {
(Some(generator_did), Some(trait_ref), Some(target_ty)) => {
(generator_did, trait_ref, target_ty)
let span = self.tcx.def_span(generator_did);
- // Do not ICE on closure typeck (#66868).
- if !generator_did.is_local() {
- return false;
- }
-
- // Get the typeck results from the infcx if the generator is the function we are
- // currently type-checking; otherwise, get them by performing a query.
- // This is needed to avoid cycles.
let in_progress_typeck_results = self.in_progress_typeck_results.map(|t| t.borrow());
- let generator_did_root = self.tcx.closure_base_def_id(generator_did);
+ let generator_did_root = self.tcx.typeck_root_def_id(generator_did);
debug!(
"maybe_note_obligation_cause_for_async_await: generator_did={:?} \
generator_did_root={:?} in_progress_typeck_results.hir_owner={:?} span={:?}",
in_progress_typeck_results.as_ref().map(|t| t.hir_owner),
span
);
- let query_typeck_results;
- let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
- Some(t) if t.hir_owner.to_def_id() == generator_did_root => t,
- _ => {
- query_typeck_results = self.tcx.typeck(generator_did.expect_local());
- &query_typeck_results
- }
- };
let generator_body = generator_did
.as_local()
let mut interior_or_upvar_span = None;
let mut interior_extra_info = None;
- if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
- interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
- let upvar_ty = typeck_results.node_type(*upvar_id);
- let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
- if ty_matches(ty::Binder::dummy(upvar_ty)) {
- Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
- } else {
- None
- }
- });
+ // Get the typeck results from the infcx if the generator is the function we are currently
+ // type-checking; otherwise, get them by performing a query. This is needed to avoid
+ // cycles. If we can't use resolved types because the generator comes from another crate,
+ // we still provide a targeted error but without all the relevant spans.
+ let query_typeck_results;
+ let typeck_results: Option<&TypeckResults<'tcx>> = match &in_progress_typeck_results {
+ Some(t) if t.hir_owner.to_def_id() == generator_did_root => Some(&t),
+ _ if generator_did.is_local() => {
+ query_typeck_results = self.tcx.typeck(generator_did.expect_local());
+ Some(&query_typeck_results)
+ }
+ _ => None, // Do not ICE on closure typeck (#66868).
};
+ if let Some(typeck_results) = typeck_results {
+ if let Some(upvars) = self.tcx.upvars_mentioned(generator_did) {
+ interior_or_upvar_span = upvars.iter().find_map(|(upvar_id, upvar)| {
+ let upvar_ty = typeck_results.node_type(*upvar_id);
+ let upvar_ty = self.resolve_vars_if_possible(upvar_ty);
+ if ty_matches(ty::Binder::dummy(upvar_ty)) {
+ Some(GeneratorInteriorOrUpvar::Upvar(upvar.span))
+ } else {
+ None
+ }
+ });
+ };
- // The generator interior types share the same binders
- if let Some(cause) =
- typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
- |ty::GeneratorInteriorTypeCause { ty, .. }| {
- ty_matches(typeck_results.generator_interior_types.rebind(ty))
- },
- )
- {
- // Check to see if any awaited expressions have the target type.
- let from_awaited_ty = visitor
- .awaits
- .into_iter()
- .map(|id| hir.expect_expr(id))
- .find(|await_expr| {
- let ty = typeck_results.expr_ty_adjusted(&await_expr);
- debug!(
- "maybe_note_obligation_cause_for_async_await: await_expr={:?}",
- await_expr
- );
- ty_matches(ty::Binder::dummy(ty))
- })
- .map(|expr| expr.span);
- let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } = cause;
+ // The generator interior types share the same binders
+ if let Some(cause) =
+ typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
+ |ty::GeneratorInteriorTypeCause { ty, .. }| {
+ ty_matches(typeck_results.generator_interior_types.rebind(ty))
+ },
+ )
+ {
+ // Check to see if any awaited expressions have the target type.
+ let from_awaited_ty = visitor
+ .awaits
+ .into_iter()
+ .map(|id| hir.expect_expr(id))
+ .find(|await_expr| {
+ ty_matches(ty::Binder::dummy(typeck_results.expr_ty_adjusted(&await_expr)))
+ })
+ .map(|expr| expr.span);
+ let ty::GeneratorInteriorTypeCause { span, scope_span, yield_span, expr, .. } =
+ cause;
- interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
- interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
- };
+ interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(*span));
+ interior_extra_info = Some((*scope_span, *yield_span, *expr, from_awaited_ty));
+ };
+ } else {
+ interior_or_upvar_span = Some(GeneratorInteriorOrUpvar::Interior(span));
+ }
- debug!(
- "maybe_note_obligation_cause_for_async_await: interior_or_upvar={:?} \
- generator_interior_types={:?}",
- interior_or_upvar_span, typeck_results.generator_interior_types
- );
if let Some(interior_or_upvar_span) = interior_or_upvar_span {
self.note_obligation_cause_for_async_await(
err,
outer_generator: Option<DefId>,
trait_ref: ty::TraitRef<'tcx>,
target_ty: Ty<'tcx>,
- typeck_results: &ty::TypeckResults<'tcx>,
+ typeck_results: Option<&ty::TypeckResults<'tcx>>,
obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>,
) {
// Look at the last interior type to get a span for the `.await`.
debug!(
"note_obligation_cause_for_async_await generator_interior_types: {:#?}",
- typeck_results.generator_interior_types
+ typeck_results.as_ref().map(|t| &t.generator_interior_types)
);
explain_yield(interior_span, yield_span, scope_span);
}
// ^^^^^^^ a temporary `&T` created inside this method call due to `&self`
// ```
//
- let is_region_borrow = typeck_results
- .expr_adjustments(expr)
- .iter()
- .any(|adj| adj.is_region_borrow());
+ let is_region_borrow = if let Some(typeck_results) = typeck_results {
+ typeck_results
+ .expr_adjustments(expr)
+ .iter()
+ .any(|adj| adj.is_region_borrow())
+ } else {
+ false
+ };
// ```rust
// struct Foo(*const u8);
DefKind::Fn | DefKind::Ctor(..) => target_ty.is_unsafe_ptr(),
_ => false,
};
-
- if (typeck_results.is_method_call(e) && is_region_borrow)
- || is_raw_borrow_inside_fn_like_call
- {
- err.span_help(
- parent_span,
- "consider moving this into a `let` \
+ if let Some(typeck_results) = typeck_results {
+ if (typeck_results.is_method_call(e) && is_region_borrow)
+ || is_raw_borrow_inside_fn_like_call
+ {
+ err.span_help(
+ parent_span,
+ "consider moving this into a `let` \
binding to create a shorter lived borrow",
- );
+ );
+ }
}
}
}
}
/// Attempts to select obligations using `selcx`.
- fn select(
- &mut self,
- selcx: &mut SelectionContext<'a, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
let _enter = span.enter();
errors.len()
);
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ errors
}
}
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}
- fn select_all_or_error(
- &mut self,
- infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_where_possible(infcx)?;
-
- let errors: Vec<_> = self
- .predicates
- .to_errors(CodeAmbiguity)
- .into_iter()
- .map(to_fulfillment_error)
- .collect();
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_where_possible(infcx);
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
+
+ self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
fn select_all_with_constness_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: rustc_hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_with_constness_where_possible(infcx, constness)?;
-
- let errors: Vec<_> = self
- .predicates
- .to_errors(CodeAmbiguity)
- .into_iter()
- .map(to_fulfillment_error)
- .collect();
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ ) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_with_constness_where_possible(infcx, constness);
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
+
+ self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::new(infcx);
self.select(&mut selcx)
}
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: hir::Constness,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::with_constness(infcx, constness);
self.select(&mut selcx)
}
// Note: we only assume something is `Copy` if we can
// *definitively* show that it implements `Copy`. Otherwise,
// assume it is move; linear is always ok.
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => {
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => {
debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
ty,
);
true
}
- Err(e) => {
+ errors => {
debug!(
- "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}",
- ty,
- infcx.tcx.def_path_str(def_id),
- e
+ ?ty,
+ bound = %infcx.tcx.def_path_str(def_id),
+ ?errors,
+ "type_known_to_meet_bound_modulo_regions"
);
false
}
}
debug!("fully_normalize: select_all_or_error start");
- fulfill_cx.select_all_or_error(infcx)?;
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
+ return Err(errors);
+ }
debug!("fully_normalize: select_all_or_error complete");
let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
debug!("fully_normalize: resolved_value={:?}", resolved_value);
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
- fulfill_cx.select_all_or_error(&infcx).is_err()
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+
+ !errors.is_empty()
});
debug!("impossible_predicates = {:?}", result);
result
) -> usize {
let (trait_to_be_found, trait_owning_vtable) = key;
+ // #90177
+ let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found);
+
let vtable_segment_callback = {
let mut vtable_base = 0;
vtable_base += COMMON_VTABLE_ENTRIES.len();
}
VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => {
- if trait_ref == trait_to_be_found {
+ if tcx.erase_regions(trait_ref) == trait_to_be_found_erased {
return ControlFlow::Break(vtable_base);
}
vtable_base += util::count_own_vtable_entries(tcx, trait_ref);
ty: ret_type,
});
- confirm_param_env_candidate(selcx, obligation, predicate, false)
+ confirm_param_env_candidate(selcx, obligation, predicate, true)
}
fn confirm_param_env_candidate<'cx, 'tcx>(
);
let cache_projection = cache_entry.projection_ty;
- let obligation_projection = obligation.predicate;
let mut nested_obligations = Vec::new();
+ let obligation_projection = obligation.predicate;
+ let obligation_projection = ensure_sufficient_stack(|| {
+ normalize_with_depth_to(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation_projection,
+ &mut nested_obligations,
+ )
+ });
let cache_projection = if potentially_unnormalized_candidate {
ensure_sufficient_stack(|| {
normalize_with_depth_to(
cache_projection
};
+ debug!(?cache_projection, ?obligation_projection);
+
match infcx.at(cause, param_env).eq(cache_projection, obligation_projection) {
Ok(InferOk { value: _, obligations }) => {
nested_obligations.extend(obligations);
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(infcx, obligations);
- if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
+ let errors = fulfill_cx.select_all_or_error(infcx);
+ if !errors.is_empty() {
infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP,
- &format!("errors selecting obligation during MIR typeck: {:?}", e),
+ &format!("errors selecting obligation during MIR typeck: {:?}", errors),
);
}
_ => bug!("closure candidate for non-closure {:?}", obligation),
};
+ let obligation_predicate = obligation.predicate.to_poly_trait_ref();
+ let Normalized { value: obligation_predicate, mut obligations } =
+ ensure_sufficient_stack(|| {
+ normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ obligation_predicate,
+ )
+ });
+
let trait_ref = self.closure_trait_ref_unnormalized(obligation, substs);
- let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| {
- normalize_with_depth(
- self,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- trait_ref,
- )
- });
+ let Normalized { value: trait_ref, obligations: trait_ref_obligations } =
+ ensure_sufficient_stack(|| {
+ normalize_with_depth(
+ self,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ trait_ref,
+ )
+ });
debug!(?closure_def_id, ?trait_ref, ?obligations, "confirm closure candidate obligations");
+ obligations.extend(trait_ref_obligations);
obligations.extend(self.confirm_poly_trait_refs(
obligation.cause.clone(),
obligation.param_env,
- obligation.predicate.to_poly_trait_ref(),
+ obligation_predicate,
trait_ref,
)?);
let tail_field_ty = tcx.type_of(tail_field.did);
let mut unsizing_params = GrowableBitSet::new_empty();
- if tcx.features().relaxed_struct_unsize {
- for arg in tail_field_ty.walk(tcx) {
- if let Some(i) = maybe_unsizing_param_idx(arg) {
- unsizing_params.insert(i);
- }
- }
-
- // Ensure none of the other fields mention the parameters used
- // in unsizing.
- for field in prefix_fields {
- for arg in tcx.type_of(field.did).walk(tcx) {
- if let Some(i) = maybe_unsizing_param_idx(arg) {
- unsizing_params.remove(i);
- }
- }
+ for arg in tail_field_ty.walk(tcx) {
+ if let Some(i) = maybe_unsizing_param_idx(arg) {
+ unsizing_params.insert(i);
}
+ }
- if unsizing_params.is_empty() {
- return Err(Unimplemented);
- }
- } else {
- let mut found = false;
- for arg in tail_field_ty.walk(tcx) {
+ // Ensure none of the other fields mention the parameters used
+ // in unsizing.
+ for field in prefix_fields {
+ for arg in tcx.type_of(field.did).walk(tcx) {
if let Some(i) = maybe_unsizing_param_idx(arg) {
- unsizing_params.insert(i);
- found = true;
+ unsizing_params.remove(i);
}
}
- if !found {
- return Err(Unimplemented);
- }
+ }
- // Ensure none of the other fields mention the parameters used
- // in unsizing.
- // FIXME(eddyb) cache this (including computing `unsizing_params`)
- // by putting it in a query; it would only need the `DefId` as it
- // looks at declared field types, not anything substituted.
- for field in prefix_fields {
- for arg in tcx.type_of(field.did).walk(tcx) {
- if let Some(i) = maybe_unsizing_param_idx(arg) {
- if unsizing_params.contains(i) {
- return Err(Unimplemented);
- }
- }
- }
- }
+ if unsizing_params.is_empty() {
+ return Err(Unimplemented);
}
// Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`.
/// Returns `true` if the trait predicate is considerd `const` to this selection context.
pub fn is_trait_predicate_const(&self, pred: ty::TraitPredicate<'_>) -> bool {
- match pred.constness {
- ty::BoundConstness::ConstIfConst if self.is_in_const_context => true,
- _ => false,
- }
+ matches!(pred.constness, ty::BoundConstness::ConstIfConst) && self.is_in_const_context
}
/// Returns `true` if the predicate is considered `const` to
// Check if a bound would previously have been removed when normalizing
// the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this.
- let is_global =
- |cand: &ty::PolyTraitRef<'_>| cand.is_known_global() && !cand.has_late_bound_regions();
+ let is_global = |cand: &ty::PolyTraitRef<'tcx>| {
+ cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
+ };
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
// and `DiscriminantKindCandidate` to anything else.
for oblig in obligations.chain(more_obligations) {
fulfill_cx.register_predicate_obligation(&infcx, oblig);
}
- match fulfill_cx.select_all_or_error(infcx) {
- Err(errors) => {
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => {
+ debug!(
+ "fulfill_implication: an impl for {:?} specializes {:?}",
+ source_trait_ref, target_trait_ref
+ );
+
+ // Now resolve the *substitution* we built for the target earlier, replacing
+ // the inference variables inside with whatever we got from fulfillment.
+ Ok(infcx.resolve_vars_if_possible(target_substs))
+ }
+ errors => {
// no dice!
debug!(
"fulfill_implication: for impls on {:?} and {:?}, \
);
Err(())
}
-
- Ok(()) => {
- debug!(
- "fulfill_implication: an impl for {:?} specializes {:?}",
- source_trait_ref, target_trait_ref
- );
-
- // Now resolve the *substitution* we built for the target earlier, replacing
- // the inference variables inside with whatever we got from fulfillment.
- Ok(infcx.resolve_vars_if_possible(target_substs))
- }
}
})
}
//
// 2. We are sometimes doing future-incompatibility lints for
// now, so we do not want unconditional errors here.
- fulfillment_cx.select_all_or_error(infcx).is_ok()
+ fulfillment_cx.select_all_or_error(infcx).is_empty()
}
/// This implements the traversal over the structure of a given type to try to
// Ensure that those obligations that we had to solve
// get solved *here*.
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => Ok(implied_bounds),
- Err(_) => Err(NoSolution),
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => Ok(implied_bounds),
+ _ => Err(NoSolution),
}
}
type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
- let adt_components =
- move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
-
// If we don't know a type doesn't need drop, for example if it's a type
// parameter without a `Copy` bound, then we conservatively return that it
// needs drop.
- let res =
- NeedsDropTypes::new(tcx, query.param_env, query.value, adt_components).next().is_some();
+ let adt_has_dtor =
+ |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
+ let res = drop_tys_helper(tcx, query.value, query.param_env, adt_has_dtor).next().is_some();
debug!("needs_drop_raw({:?}) = {:?}", query, res);
res
tcx: TyCtxt<'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> bool {
- let significant_drop_fields = move |adt_def: &ty::AdtDef, _| {
- tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter())
- };
- let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields)
- .next()
- .is_some();
+ let res =
+ drop_tys_helper(tcx, query.value, query.param_env, adt_consider_insignificant_dtor(tcx))
+ .next()
+ .is_some();
debug!("has_significant_drop_raw({:?}) = {:?}", query, res);
res
}
Ok(tys) => tys,
};
for required_ty in tys {
- let subst_ty = tcx.normalize_erasing_regions(
- self.param_env,
- required_ty.subst(tcx, substs),
- );
+ let subst_ty =
+ tcx.normalize_erasing_regions(self.param_env, required_ty);
queue_type(self, subst_ty);
}
}
// Depending on the implentation of `adt_has_dtor`, it is used to check if the
// ADT has a destructor or if the ADT only has a significant destructor. For
// understanding significant destructor look at `adt_significant_drop_tys`.
-fn adt_drop_tys_helper<'tcx>(
+fn drop_tys_helper<'tcx>(
tcx: TyCtxt<'tcx>,
- def_id: DefId,
+ ty: Ty<'tcx>,
+ param_env: rustc_middle::ty::ParamEnv<'tcx>,
adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
-) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
+) -> impl Iterator<Item = NeedsDropResult<Ty<'tcx>>> {
let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
if adt_def.is_manually_drop() {
- debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
+ debug!("drop_tys_helper: `{:?}` is manually drop", adt_def);
return Ok(Vec::new().into_iter());
} else if let Some(dtor_info) = adt_has_dtor(adt_def) {
match dtor_info {
DtorType::Significant => {
- debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
+ debug!("drop_tys_helper: `{:?}` implements `Drop`", adt_def);
return Err(AlwaysRequiresDrop);
}
DtorType::Insignificant => {
- debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def);
+ debug!("drop_tys_helper: `{:?}` drop is insignificant", adt_def);
// Since the destructor is insignificant, we just want to make sure all of
// the passed in type parameters are also insignificant.
}
}
} else if adt_def.is_union() {
- debug!("adt_drop_tys: `{:?}` is a union", adt_def);
+ debug!("drop_tys_helper: `{:?}` is a union", adt_def);
return Ok(Vec::new().into_iter());
}
- Ok(adt_def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>().into_iter())
+ Ok(adt_def
+ .all_fields()
+ .map(|field| {
+ let r = tcx.type_of(field.did).subst(tcx, substs);
+ debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r);
+ r
+ })
+ .collect::<Vec<_>>()
+ .into_iter())
};
- let adt_ty = tcx.type_of(def_id);
- let param_env = tcx.param_env(def_id);
- let res: Result<Vec<_>, _> =
- NeedsDropTypes::new(tcx, param_env, adt_ty, adt_components).collect();
-
- debug!("adt_drop_tys(`{}`) = `{:?}`", tcx.def_path_str(def_id), res);
- res.map(|components| tcx.intern_type_list(&components))
+ NeedsDropTypes::new(tcx, param_env, ty, adt_components)
}
-fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
- // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are
- // significant.
- let adt_has_dtor =
- |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
- adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
-}
-
-fn adt_significant_drop_tys(
- tcx: TyCtxt<'_>,
- def_id: DefId,
-) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
- let adt_has_dtor = |adt_def: &ty::AdtDef| {
+fn adt_consider_insignificant_dtor<'tcx>(
+ tcx: TyCtxt<'tcx>,
+) -> impl Fn(&ty::AdtDef) -> Option<DtorType> + 'tcx {
+ move |adt_def: &ty::AdtDef| {
let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
if is_marked_insig {
// In some cases like `std::collections::HashMap` where the struct is a wrapper around
// treat this as the simple case of Drop impl for type.
None
}
- };
- adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
+ }
+}
+
+fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
+ // This is for the "adt_drop_tys" query, that considers all `Drop` impls, therefore all dtors are
+ // significant.
+ let adt_has_dtor =
+ |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
+ drop_tys_helper(tcx, tcx.type_of(def_id), tcx.param_env(def_id), adt_has_dtor)
+ .collect::<Result<Vec<_>, _>>()
+ .map(|components| tcx.intern_type_list(&components))
+}
+
+fn adt_significant_drop_tys(
+ tcx: TyCtxt<'_>,
+ def_id: DefId,
+) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
+ drop_tys_helper(
+ tcx,
+ tcx.type_of(def_id),
+ tcx.param_env(def_id),
+ adt_consider_insignificant_dtor(tcx),
+ )
+ .collect::<Result<Vec<_>, _>>()
+ .map(|components| tcx.intern_type_list(&components))
}
pub(crate) fn provide(providers: &mut ty::query::Providers) {
}
/// See `ParamEnv` struct definition for details.
+#[instrument(level = "debug", skip(tcx))]
fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
// The param_env of an impl Trait type is its defining function's param_env
if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
predicates.extend(environment);
}
+ // It's important that we include the default substs in unevaluated
+ // constants, since `Unevaluated` instances in predicates whose substs are None
+ // can lead to "duplicate" caller bounds candidates during trait selection,
+ // duplicate in the sense that both have their default substs, but the
+ // candidate that resulted from a superpredicate still uses `None` in its
+ // `substs_` field of `Unevaluated` to indicate that it has its default substs,
+ // whereas the other candidate has `substs_: Some(default_substs)`, see
+ // issue #89334
+ predicates = tcx.expose_default_const_substs(predicates);
+
let unnormalized_env =
ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
+ debug!("unnormalized_env caller bounds: {:?}", unnormalized_env.caller_bounds());
let body_id = def_id
.as_local()
.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
"reorder the arguments: {}: `<{}>`",
param_types_present
.into_iter()
- .map(|ord| format!("{}s", ord.to_string()))
+ .map(|ord| format!("{}s", ord))
.collect::<Vec<String>>()
.join(", then "),
ordered_params
err.span_label(span, "explicit generic argument not allowed");
}
+ err.note(
+ "see issue #83701 <https://github.com/rust-lang/rust/issues/83701> \
+ for more information",
+ );
+ if tcx.sess.is_nightly_build() {
+ err.help(
+ "add `#![feature(explicit_generic_args_with_impl_trait)]` \
+ to the crate attributes to enable",
+ );
+ }
+
err.emit();
}
use rustc_infer::traits::Obligation;
use rustc_middle::ty::{self, ToPredicate, Ty, TyS};
use rustc_span::{MultiSpan, Span};
-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,
// Very crude check to see whether the expression must be wrapped
// in parentheses for the suggestion to work (issue #89497).
// Can/should be extended in the future.
- let needs_parens = !has_parens
- && match self.expr.kind {
- hir::ExprKind::Cast(..) => true,
- _ => false,
- };
+ let needs_parens =
+ !has_parens && matches!(self.expr.kind, hir::ExprKind::Cast(..));
let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)];
if needs_parens {
use rustc_span::symbol::sym;
use rustc_span::{self, MultiSpan, Span};
use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_ty_utils::representability::{self, Representability};
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
}
// Finally, resolve all regions. This catches wily misuses of
let parent_substs = InternalSubsts::identity_for_item(
self.tcx,
- self.tcx.closure_base_def_id(expr_def_id.to_def_id()),
+ self.tcx.typeck_root_def_id(expr_def_id.to_def_id()),
);
let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin {
};
let mut fcx = traits::FulfillmentContext::new_in_snapshot();
fcx.register_predicate_obligations(self, ok.obligations);
- fcx.select_where_possible(&self).is_ok()
+ fcx.select_where_possible(&self).is_empty()
})
}
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
Ok(())
}
+#[instrument(level = "debug", skip(infcx))]
fn extract_spans_for_error_reporting<'a, 'tcx>(
infcx: &infer::InferCtxt<'a, 'tcx>,
terr: &TypeError<'_>,
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return;
}
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
// Check that all obligations are satisfied by the implementation's
// version.
- if let Err(ref errors) =
- inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness)
- {
- infcx.report_fulfillment_errors(errors, None, false);
+ let errors =
+ inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
) {
self.annotate_expected_due_to_let_ty(err, expr);
+ self.suggest_box_deref(err, expr, expected, expr_ty);
self.suggest_compatible_variants(err, expr, expected, expr_ty);
self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
}
}
+ fn suggest_box_deref(
+ &self,
+ err: &mut DiagnosticBuilder<'_>,
+ expr: &hir::Expr<'_>,
+ expected: Ty<'tcx>,
+ expr_ty: Ty<'tcx>,
+ ) {
+ if expr_ty.is_box() && expr_ty.boxed_ty() == expected {
+ err.span_suggestion_verbose(
+ expr.span.shrink_to_lo(),
+ "try dereferencing the `Box`",
+ "*".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+
/// If the expected type is an enum (Issue #55250) with any variants whose
/// sole field is of the found type, suggest such variants. (Issue #42764)
fn suggest_compatible_variants(
(&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind {
if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(_) = replace_prefix(&src, "b\"", "\"") {
+ if replace_prefix(&src, "b\"", "\"").is_some() {
let pos = sp.lo() + BytePos(1);
return Some((
sp.with_hi(pos),
(&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind {
if let Ok(src) = sm.span_to_snippet(sp) {
- if let Some(_) = replace_prefix(&src, "\"", "b\"") {
+ if replace_prefix(&src, "\"", "b\"").is_some() {
return Some((
sp.shrink_to_lo(),
"consider adding a leading `b`",
}
}
- if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
// this could be reached when we get lazy normalization
- infcx.report_fulfillment_errors(errors, None, false);
+ infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, QPath};
use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
}
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
- ExprKind::ConstBlock(ref anon_const) => self.to_const(anon_const).ty,
+ ExprKind::ConstBlock(ref anon_const) => {
+ self.check_expr_const_block(anon_const, expected, expr)
+ }
ExprKind::Repeat(element, ref count) => {
self.check_expr_repeat(element, count, expected, expr)
}
self.tcx.mk_array(element_ty, args.len() as u64)
}
+ fn check_expr_const_block(
+ &self,
+ anon_const: &'tcx hir::AnonConst,
+ expected: Expectation<'tcx>,
+ _expr: &'tcx hir::Expr<'tcx>,
+ ) -> Ty<'tcx> {
+ let body = self.tcx.hir().body(anon_const.body);
+
+ // Create a new function context.
+ let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id);
+ crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
+
+ let ty = fcx.check_expr_with_expectation(&body.value, expected);
+ fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
+ fcx.write_ty(anon_const.hir_id, ty);
+ ty
+ }
+
fn check_expr_repeat(
&self,
element: &'tcx hir::Expr<'tcx>,
// Save the index of all fields regardless of their visibility in case
// of error recovery.
self.write_field_index(expr.hir_id, index);
+ let adjustments = self.adjust_steps(&autoderef);
if field.vis.is_accessible_from(def_scope, self.tcx) {
- let adjustments = self.adjust_steps(&autoderef);
self.apply_adjustments(base, adjustments);
self.register_predicates(autoderef.into_obligations());
self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
return field_ty;
}
- private_candidate = Some((base_def.did, field_ty));
+ private_candidate = Some((adjustments, base_def.did, field_ty));
}
}
ty::Tuple(tys) => {
}
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
- if let Some((did, field_ty)) = private_candidate {
+ if let Some((adjustments, did, field_ty)) = private_candidate {
+ // (#90483) apply adjustments to avoid ExprUseVisitor from
+ // creating erroneous projection.
+ self.apply_adjustments(base, adjustments);
self.ban_private_field_access(expr, expr_t, field, did);
return field_ty;
}
) -> Option<(&Vec<ty::FieldDef>, SubstsRef<'tcx>)> {
debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
- let mut autoderef = self.autoderef(span, base_t);
- while let Some((base_t, _)) = autoderef.next() {
+ for (base_t, _) in self.autoderef(span, base_t) {
match base_t.kind() {
ty::Adt(base_def, substs) if !base_def.is_enum() => {
let fields = &base_def.non_enum_variant().fields;
.type_var_origin(ty)
.map(|origin| origin.span)
.unwrap_or(rustc_span::DUMMY_SP);
- let oty = self.inner.borrow().opaque_types_vars.get(ty).map(|v| *v);
+ let oty = self.inner.borrow().opaque_types_vars.get(ty).copied();
if let Some(opaque_ty) = oty {
debug!(
"fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{self, BytePos, MultiSpan, Span};
use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use rustc_trait_selection::traits::{
self, ObligationCause, ObligationCauseCode, StatementAsExpression, TraitEngine, TraitEngineExt,
#[instrument(skip(self), level = "debug")]
pub(in super::super) fn select_all_obligations_or_error(&self) {
- if let Err(errors) = self
+ let errors = self
.fulfillment_cx
.borrow_mut()
- .select_all_with_constness_or_error(&self, self.inh.constness)
- {
+ .select_all_with_constness_or_error(&self, self.inh.constness);
+
+ if !errors.is_empty() {
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
}
}
fallback_has_occurred: bool,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) {
- let result = self
+ let mut result = self
.fulfillment_cx
.borrow_mut()
.select_with_constness_where_possible(self, self.inh.constness);
- if let Err(mut errors) = result {
- mutate_fulfillment_errors(&mut errors);
- self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
+ if !result.is_empty() {
+ mutate_fulfillment_errors(&mut result);
+ self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
}
}
// we can. We don't care if some things turn
// out unconstrained or ambiguous, as we're
// just trying to get hints here.
- self.save_and_restore_in_snapshot_flag(|_| {
+ let errors = self.save_and_restore_in_snapshot_flag(|_| {
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
for obligation in ok.obligations {
fulfill.register_predicate_obligation(self, obligation);
}
fulfill.select_where_possible(self)
- })
- .map_err(|_| ())?;
+ });
+
+ if !errors.is_empty() {
+ return Err(());
+ }
}
Err(_) => return Err(()),
}
self.tcx.type_of(def_id)
};
let substs = self.infcx.fresh_substs_for_item(span, def_id);
- self.write_substs(hir_id, substs);
let ty = item_ty.subst(self.tcx, substs);
self.write_resolution(hir_id, Ok((def_kind, def_id)));
// `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
+ final_arg_types.push((i, checked_ty, coerce_ty));
+
// Cause selection errors caused by resolving a single argument to point at the
// argument and not the call. This is otherwise redundant with the `demand_coerce`
// call immediately after, but it lets us customize the span pointed to in the
let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
coerce_ty,
|errors| {
- // This is not coming from a macro or a `derive`.
- if sp.desugaring_kind().is_none()
- && !arg.span.from_expansion()
- // Do not change the spans of `async fn`s.
- && !matches!(
- expr.kind,
- hir::ExprKind::Call(
- hir::Expr {
- kind: hir::ExprKind::Path(hir::QPath::LangItem(_, _)),
- ..
- },
- _
- )
- ) {
- for error in errors {
- error.obligation.cause.make_mut().span = arg.span;
- let code = error.obligation.cause.code.clone();
- error.obligation.cause.make_mut().code =
- ObligationCauseCode::FunctionArgumentObligation {
- arg_hir_id: arg.hir_id,
- call_hir_id: expr.hir_id,
- parent_code: Lrc::new(code),
- };
- }
- }
+ self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
+ self.point_at_arg_instead_of_call_if_possible(
+ errors,
+ &final_arg_types,
+ expr,
+ sp,
+ args,
+ );
},
);
// We're processing function arguments so we definitely want to use
// two-phase borrows.
self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
- final_arg_types.push((i, checked_ty, coerce_ty));
// 3. Relate the expected type and the formal one,
// if the expected type was used for the coercion.
continue;
}
- if let ty::PredicateKind::Trait(predicate) =
- error.obligation.predicate.kind().skip_binder()
- {
- // Collect the argument position for all arguments that could have caused this
- // `FulfillmentError`.
- let mut referenced_in = final_arg_types
- .iter()
- .map(|&(i, checked_ty, _)| (i, checked_ty))
- .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
- .flat_map(|(i, ty)| {
- let ty = self.resolve_vars_if_possible(ty);
- // We walk the argument type because the argument's type could have
- // been `Option<T>`, but the `FulfillmentError` references `T`.
- if ty.walk(self.tcx).any(|arg| arg == predicate.self_ty().into()) {
- Some(i)
- } else {
- None
- }
- })
- .collect::<Vec<usize>>();
-
- // Both checked and coerced types could have matched, thus we need to remove
- // duplicates.
-
- // 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()) {
- // We make sure that only *one* argument matches the obligation failure
- // and we assign the obligation's span to its expression's.
- error.obligation.cause.make_mut().span = args[ref_in].span;
- let code = error.obligation.cause.code.clone();
- error.obligation.cause.make_mut().code =
- ObligationCauseCode::FunctionArgumentObligation {
- arg_hir_id: args[ref_in].hir_id,
- call_hir_id: expr.hir_id,
- parent_code: Lrc::new(code),
- };
+ // Peel derived obligation, because it's the type that originally
+ // started this inference chain that matters, not the one we wound
+ // up with at the end.
+ fn unpeel_to_top(
+ mut code: Lrc<ObligationCauseCode<'_>>,
+ ) -> Lrc<ObligationCauseCode<'_>> {
+ let mut result_code = code.clone();
+ loop {
+ let parent = match &*code {
+ ObligationCauseCode::BuiltinDerivedObligation(c)
+ | ObligationCauseCode::ImplDerivedObligation(c)
+ | ObligationCauseCode::DerivedObligation(c) => c.parent_code.clone(),
+ _ => break,
+ };
+ result_code = std::mem::replace(&mut code, parent);
+ }
+ result_code
+ }
+ let self_: ty::subst::GenericArg<'_> = match &*unpeel_to_top(Lrc::new(error.obligation.cause.code.clone())) {
+ ObligationCauseCode::BuiltinDerivedObligation(code) |
+ ObligationCauseCode::ImplDerivedObligation(code) |
+ ObligationCauseCode::DerivedObligation(code) => {
+ code.parent_trait_ref.self_ty().skip_binder().into()
+ }
+ _ if let ty::PredicateKind::Trait(predicate) =
+ error.obligation.predicate.kind().skip_binder() => {
+ predicate.self_ty().into()
+ }
+ _ => continue,
+ };
+ let self_ = self.resolve_vars_if_possible(self_);
+
+ // Collect the argument position for all arguments that could have caused this
+ // `FulfillmentError`.
+ let mut referenced_in = final_arg_types
+ .iter()
+ .map(|&(i, checked_ty, _)| (i, checked_ty))
+ .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
+ .flat_map(|(i, ty)| {
+ let ty = self.resolve_vars_if_possible(ty);
+ // We walk the argument type because the argument's type could have
+ // been `Option<T>`, but the `FulfillmentError` references `T`.
+ if ty.walk(self.tcx).any(|arg| arg == self_) { Some(i) } else { None }
+ })
+ .collect::<Vec<usize>>();
+
+ // Both checked and coerced types could have matched, thus we need to remove
+ // duplicates.
+
+ // 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()) {
+ // Do not point at the inside of a macro.
+ // That would often result in poor error messages.
+ if args[ref_in].span.from_expansion() {
+ return;
+ }
+ // We make sure that only *one* argument matches the obligation failure
+ // and we assign the obligation's span to its expression's.
+ error.obligation.cause.make_mut().span = args[ref_in].span;
+ let code = error.obligation.cause.code.clone();
+ error.obligation.cause.make_mut().code =
+ ObligationCauseCode::FunctionArgumentObligation {
+ arg_hir_id: args[ref_in].hir_id,
+ call_hir_id: expr.hir_id,
+ parent_code: Lrc::new(code),
+ };
+ } else if error.obligation.cause.make_mut().span == call_sp {
+ // Make function calls point at the callee, not the whole thing.
+ if let hir::ExprKind::Call(callee, _) = expr.kind {
+ error.obligation.cause.make_mut().span = callee.span;
}
}
}
call_expr: &'tcx hir::Expr<'tcx>,
) {
if let hir::ExprKind::Call(path, _) = &call_expr.kind {
- if let hir::ExprKind::Path(qpath) = &path.kind {
- if let hir::QPath::Resolved(_, path) = &qpath {
- for error in errors {
- if let ty::PredicateKind::Trait(predicate) =
- error.obligation.predicate.kind().skip_binder()
+ if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &path.kind {
+ for error in errors {
+ if let ty::PredicateKind::Trait(predicate) =
+ error.obligation.predicate.kind().skip_binder()
+ {
+ // If any of the type arguments in this path segment caused the
+ // `FulfillmentError`, point at its span (#61860).
+ for arg in path
+ .segments
+ .iter()
+ .filter_map(|seg| seg.args.as_ref())
+ .flat_map(|a| a.args.iter())
{
- // If any of the type arguments in this path segment caused the
- // `FulfillmentError`, point at its span (#61860).
- for arg in path
- .segments
- .iter()
- .filter_map(|seg| seg.args.as_ref())
- .flat_map(|a| a.args.iter())
- {
- if let hir::GenericArg::Type(hir_ty) = &arg {
- if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
- &hir_ty.kind
- {
- // Avoid ICE with associated types. As this is best
- // effort only, it's ok to ignore the case. It
- // would trigger in `is_send::<T::AssocType>();`
- // from `typeck-default-trait-impl-assoc-type.rs`.
- } else {
- let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty);
- let ty = self.resolve_vars_if_possible(ty);
- if ty == predicate.self_ty() {
- error.obligation.cause.make_mut().span = hir_ty.span;
- }
+ if let hir::GenericArg::Type(hir_ty) = &arg {
+ if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) =
+ &hir_ty.kind
+ {
+ // Avoid ICE with associated types. As this is best
+ // effort only, it's ok to ignore the case. It
+ // would trigger in `is_send::<T::AssocType>();`
+ // from `typeck-default-trait-impl-assoc-type.rs`.
+ } else {
+ let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, hir_ty);
+ let ty = self.resolve_vars_if_possible(ty);
+ if ty == predicate.self_ty() {
+ error.obligation.cause.make_mut().span = hir_ty.span;
}
}
}
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc_span::lev_distance;
use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{source_map, FileName, MultiSpan, Span};
+use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
use rustc_trait_selection::traits::{FulfillmentError, Obligation};
let mut candidates = valid_out_of_scope_traits;
candidates.sort();
candidates.dedup();
+
+ // `TryFrom` and `FromIterator` have no methods
+ let edition_fix = candidates
+ .iter()
+ .find(|did| self.tcx.is_diagnostic_item(sym::TryInto, **did))
+ .copied();
+
err.help("items from traits can only be used if the trait is in scope");
let msg = format!(
"the following {traits_are} implemented but not in scope; \
);
self.suggest_use_candidates(err, msg, candidates);
+ if let Some(did) = edition_fix {
+ err.note(&format!(
+ "'{}' is included in the prelude starting in Edition 2021",
+ with_crate_prefix(|| self.tcx.def_path_str(did))
+ ));
+ }
+
true
} else {
false
self.tcx.lang_items().deref_trait(),
self.tcx.lang_items().deref_mut_trait(),
self.tcx.lang_items().drop_trait(),
+ self.tcx.get_diagnostic_item(sym::AsRef),
];
// Try alternative arbitrary self types that could fulfill this call.
// FIXME: probe for all types that *could* be arbitrary self-types, not
// We don't want to suggest a container type when the missing
// method is `.clone()` or `.deref()` otherwise we'd suggest
// `Arc::new(foo).clone()`, which is far from what the user wants.
- let skip = skippable.contains(&did);
+ // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
+ // implement the `AsRef` trait.
+ let skip = skippable.contains(&did)
+ || (("Pin::new" == *pre)
+ && (Symbol::intern("as_ref") == item_name.name));
// Make sure the method is defined for the *actual* receiver: we don't
// want to treat `Box<Self>` as a receiver if it only works because of
// an autoderef to `&self`
fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
- let outer_def_id = tcx.closure_base_def_id(def_id);
- if outer_def_id != def_id {
- return tcx.has_typeck_results(outer_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
+ if typeck_root_def_id != def_id {
+ return tcx.has_typeck_results(typeck_root_def_id);
}
if let Some(def_id) = def_id.as_local() {
) -> &'tcx ty::TypeckResults<'tcx> {
// Closures' typeck results come from their outermost function,
// as they are part of the same "inference environment".
- let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
- if outer_def_id != def_id {
- return tcx.typeck(outer_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+ if typeck_root_def_id != def_id {
+ return tcx.typeck(typeck_root_def_id);
}
let id = tcx.hir().local_def_id_to_hir_id(def_id);
}
};
if let Ref(_, rty, _) = lhs_ty.kind() {
- if {
- self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span)
- && self
- .lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign))
- .is_ok()
- } {
+ if self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span)
+ && self.lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign)).is_ok()
+ {
if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
let msg = &format!(
"`{}{}` can be used on `{}`, you can dereference `{}`",
self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys));
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
fulfill.register_predicate_obligation(self, obligation);
- Err(match fulfill.select_where_possible(&self.infcx) {
- Err(errors) => errors,
- _ => vec![],
- })
+ Err(fulfill.select_where_possible(&self.infcx))
}
}
}
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
// All other literals result in non-reference types.
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`.
- PatKind::Lit(lt) => match self.check_expr(lt).kind() {
+ //
+ // Call `resolve_vars_if_possible` here for inline const blocks.
+ PatKind::Lit(lt) => match self.resolve_vars_if_possible(self.check_expr(lt)).kind() {
ty::Ref(..) => AdjustMode::Pass,
_ => AdjustMode::Peel,
},
use rustc_middle::ty::adjustment;
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
-use rustc_trait_selection::opaque_types::InferCtxtExt as _;
use std::ops::Deref;
// a variation on try that just returns unit
};
}
-trait OutlivesEnvironmentExt<'tcx> {
+pub(crate) trait OutlivesEnvironmentExt<'tcx> {
fn add_implied_bounds(
&mut self,
infcx: &InferCtxt<'a, 'tcx>,
self.link_fn_params(body.params);
self.visit_body(body);
self.visit_region_obligations(body_id.hir_id);
+ }
+
+ fn visit_inline_const(&mut self, id: hir::HirId, body: &'tcx hir::Body<'tcx>) {
+ debug!("visit_inline_const(id={:?})", id);
+
+ // Save state of current function. We will restore afterwards.
+ let old_body_id = self.body_id;
+ let old_body_owner = self.body_owner;
+ let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
- self.constrain_opaque_types();
+ let body_id = body.id();
+ self.body_id = body_id.hir_id;
+ self.body_owner = self.tcx.hir().body_owner_def_id(body_id);
+
+ self.outlives_environment.save_implied_bounds(body_id.hir_id);
+
+ self.visit_body(body);
+ self.visit_region_obligations(body_id.hir_id);
+
+ // Restore state from previous function.
+ self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
+ self.body_id = old_body_id;
+ self.body_owner = old_body_owner;
}
fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
// `visit_fn_body`. We will restore afterwards.
let old_body_id = self.body_id;
let old_body_owner = self.body_owner;
- let env_snapshot = self.outlives_environment.push_snapshot_pre_closure();
+ let env_snapshot = self.outlives_environment.push_snapshot_pre_typeck_child();
let body = self.tcx.hir().body(body_id);
self.visit_fn_body(hir_id, body, span);
// Restore state from previous function.
- self.outlives_environment.pop_snapshot_post_closure(env_snapshot);
+ self.outlives_environment.pop_snapshot_post_typeck_child(env_snapshot);
self.body_id = old_body_id;
self.body_owner = old_body_owner;
}
intravisit::walk_expr(self, expr);
}
+ hir::ExprKind::ConstBlock(anon_const) => {
+ let body = self.tcx.hir().body(anon_const.body);
+ self.visit_inline_const(anon_const.hir_id, body);
+ }
+
_ => intravisit::walk_expr(self, expr),
}
}
/// Intermediate format to store the hir_id pointing to the use that resulted in the
/// corresponding place being captured and a String which contains the captured value's
/// name (i.e: a.b.c)
-type CapturesInfo = (Option<hir::HirId>, String);
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+enum UpvarMigrationInfo {
+ /// We previously captured all of `x`, but now we capture some sub-path.
+ CapturingPrecise { source_expr: Option<hir::HirId>, var_name: String },
+ CapturingNothing {
+ // where the variable appears in the closure (but is not captured)
+ use_span: Span,
+ },
+}
+
+/// Reasons that we might issue a migration warning.
+#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+struct MigrationWarningReason {
+ /// When we used to capture `x` in its entirety, we implemented the auto-trait(s)
+ /// in this vec, but now we don't.
+ auto_traits: Vec<&'static str>,
+
+ /// When we used to capture `x` in its entirety, we would execute some destructors
+ /// at a different time.
+ drop_order: bool,
+}
-/// Intermediate format to store information needed to generate migration lint. The tuple
-/// contains the hir_id pointing to the use that resulted in the
-/// corresponding place being captured, a String which contains the captured value's
-/// name (i.e: a.b.c) and a String which contains the reason why migration is needed for that
-/// capture
-type MigrationNeededForCapture = (Option<hir::HirId>, String, String);
+impl MigrationWarningReason {
+ fn migration_message(&self) -> String {
+ let base = "changes to closure capture in Rust 2021 will affect";
+ if !self.auto_traits.is_empty() && self.drop_order {
+ format!("{} drop order and which traits the closure implements", base)
+ } else if self.drop_order {
+ format!("{} drop order", base)
+ } else {
+ format!("{} which traits the closure implements", base)
+ }
+ }
+}
+
+/// Intermediate format to store information needed to generate a note in the migration lint.
+struct MigrationLintNote {
+ captures_info: UpvarMigrationInfo,
+
+ /// reasons why migration is needed for this capture
+ reason: MigrationWarningReason,
+}
/// Intermediate format to store the hir id of the root variable and a HashSet containing
/// information on why the root variable should be fully captured
-type MigrationDiagnosticInfo = (hir::HirId, Vec<MigrationNeededForCapture>);
+struct NeededMigration {
+ var_hir_id: hir::HirId,
+ diagnostics_info: Vec<MigrationLintNote>,
+}
struct InferBorrowKindVisitor<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
}
fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
- if let hir::ExprKind::Closure(cc, _, body_id, _, _) = expr.kind {
- let body = self.fcx.tcx.hir().body(body_id);
- self.visit_body(body);
- self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+ match expr.kind {
+ hir::ExprKind::Closure(cc, _, body_id, _, _) => {
+ let body = self.fcx.tcx.hir().body(body_id);
+ self.visit_body(body);
+ self.fcx.analyze_closure(expr.hir_id, expr.span, body_id, body, cc);
+ }
+ hir::ExprKind::ConstBlock(anon_const) => {
+ let body = self.fcx.tcx.hir().body(anon_const.body);
+ self.visit_body(body);
+ }
+ _ => {}
}
intravisit::walk_expr(self, expr);
closure_head_span,
|lint| {
let mut diagnostics_builder = lint.build(
- format!(
- "changes to closure capture in Rust 2021 will affect {}",
- reasons
- )
- .as_str(),
+ &reasons.migration_message(),
);
- for (var_hir_id, diagnostics_info) in need_migrations.iter() {
+ for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations {
// Labels all the usage of the captured variable and why they are responsible
// for migration being needed
- for (captured_hir_id, captured_name, reasons) in diagnostics_info.iter() {
- if let Some(captured_hir_id) = captured_hir_id {
- let cause_span = self.tcx.hir().span(*captured_hir_id);
- diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
- self.tcx.hir().name(*var_hir_id),
- captured_name,
- ));
+ for lint_note in diagnostics_info.iter() {
+ match &lint_note.captures_info {
+ UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => {
+ let cause_span = self.tcx.hir().span(*capture_expr_id);
+ diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
+ self.tcx.hir().name(*var_hir_id),
+ captured_name,
+ ));
+ }
+ UpvarMigrationInfo::CapturingNothing { use_span } => {
+ diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
+ self.tcx.hir().name(*var_hir_id),
+ ));
+ }
+
+ _ => { }
}
// Add a label pointing to where a captured variable affected by drop order
// is dropped
- if reasons.contains("drop order") {
+ if lint_note.reason.drop_order {
let drop_location_span = drop_location_span(self.tcx, &closure_hir_id);
- diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
- self.tcx.hir().name(*var_hir_id),
- captured_name,
- ));
+ match &lint_note.captures_info {
+ UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
+ diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
+ self.tcx.hir().name(*var_hir_id),
+ captured_name,
+ ));
+ }
+ UpvarMigrationInfo::CapturingNothing { use_span: _ } => {
+ diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
+ v = self.tcx.hir().name(*var_hir_id),
+ ));
+ }
+ }
}
// Add a label explaining why a closure no longer implements a trait
- if reasons.contains("trait implementation") {
- let missing_trait = &reasons[..reasons.find("trait implementation").unwrap() - 1];
-
- diagnostics_builder.span_label(closure_head_span, format!("in Rust 2018, this closure implements {} as `{}` implements {}, but in Rust 2021, this closure will no longer implement {} as `{}` does not implement {}",
- missing_trait,
- self.tcx.hir().name(*var_hir_id),
- missing_trait,
- missing_trait,
- captured_name,
- missing_trait,
- ));
+ for &missing_trait in &lint_note.reason.auto_traits {
+ // not capturing something anymore cannot cause a trait to fail to be implemented:
+ match &lint_note.captures_info {
+ UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
+ let var_name = self.tcx.hir().name(*var_hir_id);
+ diagnostics_builder.span_label(closure_head_span, format!("\
+ in Rust 2018, this closure implements {missing_trait} \
+ as `{var_name}` implements {missing_trait}, but in Rust 2021, \
+ this closure will no longer implement {missing_trait} \
+ because `{var_name}` is not fully captured \
+ and `{captured_name}` does not implement {missing_trait}"));
+ }
+
+ // Cannot happen: if we don't capture a variable, we impl strictly more traits
+ UpvarMigrationInfo::CapturingNothing { use_span } => span_bug!(*use_span, "missing trait from not capturing something"),
+ }
}
}
}
/// Combines all the reasons for 2229 migrations
fn compute_2229_migrations_reasons(
&self,
- auto_trait_reasons: FxHashSet<&str>,
- drop_reason: bool,
- ) -> String {
- let mut reasons = String::new();
-
- if !auto_trait_reasons.is_empty() {
- reasons = format!(
- "{} trait implementation for closure",
- auto_trait_reasons.clone().into_iter().collect::<Vec<&str>>().join(", ")
- );
- }
+ auto_trait_reasons: FxHashSet<&'static str>,
+ drop_order: bool,
+ ) -> MigrationWarningReason {
+ let mut reasons = MigrationWarningReason::default();
- if !auto_trait_reasons.is_empty() && drop_reason {
- reasons = format!("{} and ", reasons);
+ for auto_trait in auto_trait_reasons {
+ reasons.auto_traits.push(auto_trait);
}
- if drop_reason {
- reasons = format!("{}drop order", reasons);
- }
+ reasons.drop_order = drop_order;
reasons
}
min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
var_hir_id: hir::HirId,
closure_clause: hir::CaptureBy,
- ) -> Option<FxHashMap<CapturesInfo, FxHashSet<&str>>> {
+ ) -> Option<FxHashMap<UpvarMigrationInfo, FxHashSet<&'static str>>> {
let auto_traits_def_id = vec![
self.tcx.lang_items().clone_trait(),
self.tcx.lang_items().sync_trait(),
if !capture_problems.is_empty() {
problematic_captures.insert(
- (capture.info.path_expr_id, capture.to_string(self.tcx)),
+ UpvarMigrationInfo::CapturingPrecise {
+ source_expr: capture.info.path_expr_id,
+ var_name: capture.to_string(self.tcx),
+ },
capture_problems,
);
}
///
/// This function only returns a HashSet of CapturesInfo for significant drops. If there
/// are no significant drops than None is returned
+ #[instrument(level = "debug", skip(self))]
fn compute_2229_migrations_for_drop(
&self,
closure_def_id: DefId,
min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
closure_clause: hir::CaptureBy,
var_hir_id: hir::HirId,
- ) -> Option<FxHashSet<CapturesInfo>> {
+ ) -> Option<FxHashSet<UpvarMigrationInfo>> {
let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
if !ty.has_significant_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local())) {
+ debug!("does not have significant drop");
return None;
}
let Some(root_var_min_capture_list) = min_captures.and_then(|m| m.get(&var_hir_id)) else {
// The upvar is mentioned within the closure but no path starting from it is
- // used.
+ // used. This occurs when you have (e.g.)
+ //
+ // ```
+ // let x = move || {
+ // let _ = y;
+ // });
+ // ```
+ debug!("no path starting from it is used");
+
match closure_clause {
// Only migrate if closure is a move closure
- hir::CaptureBy::Value => return Some(FxHashSet::default()),
+ hir::CaptureBy::Value => {
+ let mut diagnostics_info = FxHashSet::default();
+ let upvars = self.tcx.upvars_mentioned(closure_def_id).expect("must be an upvar");
+ let upvar = upvars[&var_hir_id];
+ diagnostics_info.insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span });
+ return Some(diagnostics_info);
+ }
hir::CaptureBy::Ref => {}
}
return None;
};
+ debug!(?root_var_min_capture_list);
let mut projections_list = Vec::new();
let mut diagnostics_info = FxHashSet::default();
// Only care about captures that are moved into the closure
ty::UpvarCapture::ByValue(..) => {
projections_list.push(captured_place.place.projections.as_slice());
- diagnostics_info.insert((
- captured_place.info.path_expr_id,
- captured_place.to_string(self.tcx),
- ));
+ diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
+ source_expr: captured_place.info.path_expr_id,
+ var_name: captured_place.to_string(self.tcx),
+ });
}
ty::UpvarCapture::ByRef(..) => {}
}
}
+ debug!(?projections_list);
+ debug!(?diagnostics_info);
+
let is_moved = !projections_list.is_empty();
+ debug!(?is_moved);
let is_not_completely_captured =
root_var_min_capture_list.iter().any(|capture| !capture.place.projections.is_empty());
+ debug!(?is_not_completely_captured);
if is_moved
&& is_not_completely_captured
/// Returns a tuple containing a vector of MigrationDiagnosticInfo, as well as a String
/// containing the reason why root variables whose HirId is contained in the vector should
/// be captured
+ #[instrument(level = "debug", skip(self))]
fn compute_2229_migrations(
&self,
closure_def_id: DefId,
closure_span: Span,
closure_clause: hir::CaptureBy,
min_captures: Option<&ty::RootVariableMinCaptureList<'tcx>>,
- ) -> (Vec<MigrationDiagnosticInfo>, String) {
+ ) -> (Vec<NeededMigration>, MigrationWarningReason) {
let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) else {
- return (Vec::new(), String::new());
+ return (Vec::new(), MigrationWarningReason::default());
};
let mut need_migrations = Vec::new();
// Perform auto-trait analysis
for (&var_hir_id, _) in upvars.iter() {
- let mut responsible_captured_hir_ids = Vec::new();
+ let mut diagnostics_info = Vec::new();
let auto_trait_diagnostic = if let Some(diagnostics_info) =
self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause)
let mut capture_diagnostic = capture_diagnostic.into_iter().collect::<Vec<_>>();
capture_diagnostic.sort();
- for captured_info in capture_diagnostic.iter() {
+ for captures_info in capture_diagnostic {
// Get the auto trait reasons of why migration is needed because of that capture, if there are any
let capture_trait_reasons =
- if let Some(reasons) = auto_trait_diagnostic.get(captured_info) {
+ if let Some(reasons) = auto_trait_diagnostic.get(&captures_info) {
reasons.clone()
} else {
FxHashSet::default()
};
// Check if migration is needed because of drop reorder as a result of that capture
- let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(captured_info);
+ let capture_drop_reorder_reason = drop_reorder_diagnostic.contains(&captures_info);
// Combine all the reasons of why the root variable should be captured as a result of
// auto trait implementation issues
auto_trait_migration_reasons.extend(capture_trait_reasons.clone());
- responsible_captured_hir_ids.push((
- captured_info.0,
- captured_info.1.clone(),
- self.compute_2229_migrations_reasons(
+ diagnostics_info.push(MigrationLintNote {
+ captures_info,
+ reason: self.compute_2229_migrations_reasons(
capture_trait_reasons,
capture_drop_reorder_reason,
),
- ));
+ });
}
- if !capture_diagnostic.is_empty() {
- need_migrations.push((var_hir_id, responsible_captured_hir_ids));
+ if !diagnostics_info.is_empty() {
+ need_migrations.push(NeededMigration { var_hir_id, diagnostics_info });
}
}
(
tcx.hir().name(var_hir_id)
}
+#[instrument(level = "debug", skip(tcx))]
fn should_do_rust_2021_incompatible_closure_captures_analysis(
tcx: TyCtxt<'_>,
closure_id: hir::HirId,
/// - s2: Comma separated names of the variables being migrated.
fn migration_suggestion_for_2229(
tcx: TyCtxt<'_>,
- need_migrations: &Vec<MigrationDiagnosticInfo>,
+ need_migrations: &Vec<NeededMigration>,
) -> (String, String) {
- let need_migrations_variables =
- need_migrations.iter().map(|(v, _)| var_name(tcx, *v)).collect::<Vec<_>>();
+ let need_migrations_variables = need_migrations
+ .iter()
+ .map(|NeededMigration { var_hir_id: v, .. }| var_name(tcx, *v))
+ .collect::<Vec<_>>();
let migration_ref_concat =
need_migrations_variables.iter().map(|v| format!("&{}", v)).collect::<Vec<_>>().join(", ");
+use crate::check::regionck::OutlivesEnvironmentExt;
use crate::check::{FnCtxt, Inherited};
use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
use rustc_hir::itemlikevisit::ParItemLikeVisitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::ItemKind;
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::outlives::obligations::TypeOutlives;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::infer::{self, RegionckMode, SubregionOrigin};
use rustc_middle::hir::map as hir_map;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
+use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
- self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
+ self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitor,
+ WithConstness,
};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::Span;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
+use rustc_span::{Span, DUMMY_SP};
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, WellFormedLoc};
use std::convert::TryInto;
.emit();
}
}
+
+ check_gat_where_clauses(tcx, trait_item, encl_trait_def_id);
+}
+
+/// Require that the user writes where clauses on GATs for the implicit
+/// outlives bounds involving trait parameters in trait functions and
+/// lifetimes passed as GAT substs. See `self-outlives-lint` test.
+///
+/// This trait will be our running example. We are currently WF checking the `Item` item...
+///
+/// ```rust
+/// trait LendingIterator {
+/// type Item<'me>; // <-- WF checking this trait item
+///
+/// fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
+/// }
+/// ```
+fn check_gat_where_clauses(
+ tcx: TyCtxt<'_>,
+ trait_item: &hir::TraitItem<'_>,
+ encl_trait_def_id: DefId,
+) {
+ let item = tcx.associated_item(trait_item.def_id);
+ // If the current trait item isn't a type, it isn't a GAT
+ if !matches!(item.kind, ty::AssocKind::Type) {
+ return;
+ }
+ let generics: &ty::Generics = tcx.generics_of(trait_item.def_id);
+ // If the current associated type doesn't have any (own) params, it's not a GAT
+ // FIXME(jackh726): we can also warn in the more general case
+ if generics.params.len() == 0 {
+ return;
+ }
+ let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id);
+ let mut clauses: Option<FxHashSet<ty::Predicate<'_>>> = None;
+ // For every function in this trait...
+ // In our example, this would be the `next` method
+ for item in
+ associated_items.in_definition_order().filter(|item| matches!(item.kind, ty::AssocKind::Fn))
+ {
+ // The clauses we that we would require from this function
+ let mut function_clauses = FxHashSet::default();
+
+ let id = hir::HirId::make_owner(item.def_id.expect_local());
+ let param_env = tcx.param_env(item.def_id.expect_local());
+
+ let sig = tcx.fn_sig(item.def_id);
+ // Get the signature using placeholders. In our example, this would
+ // convert the late-bound 'a into a free region.
+ let sig = tcx.liberate_late_bound_regions(item.def_id, sig);
+ // Collect the arguments that are given to this GAT in the return type
+ // of the function signature. In our example, the GAT in the return
+ // type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments.
+ let (regions, types) =
+ GATSubstCollector::visit(tcx, trait_item.def_id.to_def_id(), sig.output());
+
+ // If both regions and types are empty, then this GAT isn't in the
+ // return type, and we shouldn't try to do clause analysis
+ // (particularly, doing so would end up with an empty set of clauses,
+ // since the current method would require none, and we take the
+ // intersection of requirements of all methods)
+ if types.is_empty() && regions.is_empty() {
+ continue;
+ }
+
+ // The types we can assume to be well-formed. In our example, this
+ // would be &'a mut Self, from the first argument.
+ let mut wf_tys = FxHashSet::default();
+ wf_tys.extend(sig.inputs());
+
+ // For each region argument (e.g., 'a in our example), check for a
+ // relationship to the type arguments (e.g., Self). If there is an
+ // outlives relationship (`Self: 'a`), then we want to ensure that is
+ // reflected in a where clause on the GAT itself.
+ for (region, region_idx) in ®ions {
+ for (ty, ty_idx) in &types {
+ // In our example, requires that Self: 'a
+ if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) {
+ debug!(?ty_idx, ?region_idx);
+ debug!("required clause: {} must outlive {}", ty, region);
+ // Translate into the generic parameters of the GAT. In
+ // our example, the type was Self, which will also be
+ // Self in the GAT.
+ let ty_param = generics.param_at(*ty_idx, tcx);
+ let ty_param = tcx.mk_ty(ty::Param(ty::ParamTy {
+ index: ty_param.index,
+ name: ty_param.name,
+ }));
+ // Same for the region. In our example, 'a corresponds
+ // to the 'me parameter.
+ let region_param = generics.param_at(*region_idx, tcx);
+ let region_param =
+ tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: region_param.def_id,
+ index: region_param.index,
+ name: region_param.name,
+ }));
+ // The predicate we expect to see. (In our example,
+ // `Self: 'me`.)
+ let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
+ ty_param,
+ region_param,
+ ));
+ let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
+ function_clauses.insert(clause);
+ }
+ }
+ }
+
+ // For each region argument (e.g., 'a in our example), also check for a
+ // relationship to the other region arguments. If there is an
+ // outlives relationship, then we want to ensure that is
+ // reflected in a where clause on the GAT itself.
+ for (region_a, region_a_idx) in ®ions {
+ for (region_b, region_b_idx) in ®ions {
+ if region_a == region_b {
+ continue;
+ }
+
+ if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) {
+ debug!(?region_a_idx, ?region_b_idx);
+ debug!("required clause: {} must outlive {}", region_a, region_b);
+ // Translate into the generic parameters of the GAT.
+ let region_a_param = generics.param_at(*region_a_idx, tcx);
+ let region_a_param =
+ tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: region_a_param.def_id,
+ index: region_a_param.index,
+ name: region_a_param.name,
+ }));
+ // Same for the region.
+ let region_b_param = generics.param_at(*region_b_idx, tcx);
+ let region_b_param =
+ tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+ def_id: region_b_param.def_id,
+ index: region_b_param.index,
+ name: region_b_param.name,
+ }));
+ // The predicate we expect to see.
+ let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
+ region_a_param,
+ region_b_param,
+ ));
+ let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
+ function_clauses.insert(clause);
+ }
+ }
+ }
+
+ // Imagine we have:
+ // ```
+ // trait Foo {
+ // type Bar<'me>;
+ // fn gimme(&self) -> Self::Bar<'_>;
+ // fn gimme_default(&self) -> Self::Bar<'static>;
+ // }
+ // ```
+ // We only want to require clauses on `Bar` that we can prove from *all* functions (in this
+ // case, `'me` can be `static` from `gimme_default`)
+ match clauses.as_mut() {
+ Some(clauses) => {
+ clauses.drain_filter(|p| !function_clauses.contains(p));
+ }
+ None => {
+ clauses = Some(function_clauses);
+ }
+ }
+ }
+
+ // If there are any missing clauses, emit an error
+ let mut clauses = clauses.unwrap_or_default();
+ debug!(?clauses);
+ if !clauses.is_empty() {
+ let written_predicates: ty::GenericPredicates<'_> =
+ tcx.explicit_predicates_of(trait_item.def_id);
+ let mut clauses: Vec<_> = clauses
+ .drain_filter(|clause| !written_predicates.predicates.iter().any(|p| &p.0 == clause))
+ .map(|clause| format!("{}", clause))
+ .collect();
+ // We sort so that order is predictable
+ clauses.sort();
+ if !clauses.is_empty() {
+ let mut err = tcx.sess.struct_span_err(
+ trait_item.span,
+ &format!("Missing required bounds on {}", trait_item.ident),
+ );
+
+ let suggestion = format!(
+ "{} {}",
+ if !trait_item.generics.where_clause.predicates.is_empty() {
+ ","
+ } else {
+ " where"
+ },
+ clauses.join(", "),
+ );
+ err.span_suggestion(
+ trait_item.generics.where_clause.tail_span_for_suggestion(),
+ "add the required where clauses",
+ suggestion,
+ Applicability::MachineApplicable,
+ );
+
+ err.emit()
+ }
+ }
+}
+
+// FIXME(jackh726): refactor some of the shared logic between the two functions below
+
+/// Given a known `param_env` and a set of well formed types, can we prove that
+/// `ty` outlives `region`.
+fn ty_known_to_outlive<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ wf_tys: &FxHashSet<Ty<'tcx>>,
+ ty: Ty<'tcx>,
+ region: ty::Region<'tcx>,
+) -> bool {
+ // Unfortunately, we have to use a new `InferCtxt` each call, because
+ // region constraints get added and solved there and we need to test each
+ // call individually.
+ tcx.infer_ctxt().enter(|infcx| {
+ let mut outlives_environment = OutlivesEnvironment::new(param_env);
+ outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
+ outlives_environment.save_implied_bounds(id);
+ let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
+
+ let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
+
+ let sup_type = ty;
+ let sub_region = region;
+
+ let origin = SubregionOrigin::from_obligation_cause(&cause, || {
+ infer::RelateParamBound(cause.span, sup_type, None)
+ });
+
+ let outlives = &mut TypeOutlives::new(
+ &infcx,
+ tcx,
+ ®ion_bound_pairs,
+ Some(infcx.tcx.lifetimes.re_root_empty),
+ param_env,
+ );
+ outlives.type_must_outlive(origin, sup_type, sub_region);
+
+ let errors = infcx.resolve_regions(
+ id.expect_owner().to_def_id(),
+ &outlives_environment,
+ RegionckMode::default(),
+ );
+
+ debug!(?errors, "errors");
+
+ // If we were able to prove that the type outlives the region without
+ // an error, it must be because of the implied or explicit bounds...
+ errors.is_empty()
+ })
+}
+
+fn region_known_to_outlive<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ id: hir::HirId,
+ param_env: ty::ParamEnv<'tcx>,
+ wf_tys: &FxHashSet<Ty<'tcx>>,
+ region_a: ty::Region<'tcx>,
+ region_b: ty::Region<'tcx>,
+) -> bool {
+ // Unfortunately, we have to use a new `InferCtxt` each call, because
+ // region constraints get added and solved there and we need to test each
+ // call individually.
+ tcx.infer_ctxt().enter(|infcx| {
+ let mut outlives_environment = OutlivesEnvironment::new(param_env);
+ outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
+ outlives_environment.save_implied_bounds(id);
+
+ let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
+
+ let origin = SubregionOrigin::from_obligation_cause(&cause, || {
+ infer::RelateRegionParamBound(cause.span)
+ });
+
+ use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
+ (&infcx).push_sub_region_constraint(origin, region_a, region_b);
+
+ let errors = infcx.resolve_regions(
+ id.expect_owner().to_def_id(),
+ &outlives_environment,
+ RegionckMode::default(),
+ );
+
+ debug!(?errors, "errors");
+
+ // If we were able to prove that the type outlives the region without
+ // an error, it must be because of the implied or explicit bounds...
+ errors.is_empty()
+ })
+}
+
+/// TypeVisitor that looks for uses of GATs like
+/// `<P0 as Trait<P1..Pn>>::GAT<Pn..Pm>` and adds the arguments `P0..Pm` into
+/// the two vectors, `regions` and `types` (depending on their kind). For each
+/// parameter `Pi` also track the index `i`.
+struct GATSubstCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ gat: DefId,
+ // Which region appears and which parameter index its subsituted for
+ regions: FxHashSet<(ty::Region<'tcx>, usize)>,
+ // Which params appears and which parameter index its subsituted for
+ types: FxHashSet<(Ty<'tcx>, usize)>,
+}
+
+impl<'tcx> GATSubstCollector<'tcx> {
+ fn visit<T: TypeFoldable<'tcx>>(
+ tcx: TyCtxt<'tcx>,
+ gat: DefId,
+ t: T,
+ ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
+ let mut visitor = GATSubstCollector {
+ tcx,
+ gat,
+ regions: FxHashSet::default(),
+ types: FxHashSet::default(),
+ };
+ t.visit_with(&mut visitor);
+ (visitor.regions, visitor.types)
+ }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
+ type BreakTy = !;
+
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
+ match t.kind() {
+ ty::Projection(p) if p.item_def_id == self.gat => {
+ for (idx, subst) in p.substs.iter().enumerate() {
+ match subst.unpack() {
+ GenericArgKind::Lifetime(lt) => {
+ self.regions.insert((lt, idx));
+ }
+ GenericArgKind::Type(t) => {
+ self.types.insert((t, idx));
+ }
+ _ => {}
+ }
+ }
+ }
+ _ => {}
+ }
+ t.super_visit_with(self)
+ }
+
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
}
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
hir::ExprKind::Field(..) => {
self.visit_field_id(e.hir_id);
}
+ hir::ExprKind::ConstBlock(anon_const) => {
+ self.visit_node_id(e.span, anon_const.hir_id);
+
+ let body = self.tcx().hir().body(anon_const.body);
+ self.visit_body(body);
+ }
_ => {}
}
let coerced_fields = fields
.iter()
- .filter_map(|field| {
+ .filter(|field| {
let ty_a = field.ty(tcx, substs_a);
let ty_b = field.ty(tcx, substs_b);
if let Ok(layout) = tcx.layout_of(param_env.and(ty_a)) {
if layout.is_zst() && layout.align.abi.bytes() == 1 {
// ignore ZST fields with alignment of 1 byte
- return None;
+ return false;
}
}
))
.emit();
- return None;
+ return false;
}
}
- Some(field)
+ return true;
})
.collect::<Vec<_>>();
}
// Check that all transitive obligations are satisfied.
- if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}
fulfill_cx.register_predicate_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied.
- if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
+ let errors = fulfill_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}
{
Some(parent_def_id.to_def_id())
}
-
+ Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
+ Some(tcx.typeck_root_def_id(def_id))
+ }
_ => None,
}
}
}
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
- Some(tcx.closure_base_def_id(def_id))
+ Some(tcx.typeck_root_def_id(def_id))
}
Node::Item(item) => match item.kind {
ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
}));
}
+ // provide junk type parameter defs for const blocks.
+ if let Node::AnonConst(_) = node {
+ let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
+ if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
+ params.push(ty::GenericParamDef {
+ index: type_start,
+ name: Symbol::intern("<const_ty>"),
+ def_id,
+ pure_wrt_drop: false,
+ kind: ty::GenericParamDefKind::Type {
+ has_default: false,
+ object_lifetime_default: rl::Set1::Empty,
+ synthetic: None,
+ },
+ });
+ }
+ }
+
let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
ty::Generics {
for item in list.iter() {
if item.has_name(sym::address) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::ADDRESS;
+ } else if item.has_name(sym::cfi) {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI;
} else if item.has_name(sym::memory) {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY;
} else if item.has_name(sym::thread) {
// Getting this wrong can lead to ICE and unsoundness, so we assert it here.
for arg in substs.iter() {
let allowed_flags = ty::TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS
- | ty::TypeFlags::STILL_FURTHER_SPECIALIZABLE;
+ | ty::TypeFlags::STILL_FURTHER_SPECIALIZABLE
+ | ty::TypeFlags::HAS_ERROR;
assert!(!arg.has_type_flags(!allowed_flags));
}
substs
Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
if anon_const.hir_id == hir_id =>
{
- tcx.typeck(def_id).node_type(anon_const.hir_id)
+ let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+ substs.as_inline_const().ty()
}
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
} else {
err.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+ &format!("however, the inferred type `{}` cannot be named", ty),
);
}
}
} else {
diag.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{}` cannot be named", ty.to_string()),
+ &format!("however, the inferred type `{}` cannot be named", ty),
);
}
}
),
);
- if let Err(errors) = fulfill.select_all_or_error(&infcx) {
+ let errors = fulfill.select_all_or_error(&infcx);
+ if !errors.is_empty() {
tracing::debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
for error in errors {
if error.obligation.predicate == self.predicate {
#![feature(never_type)]
#![feature(slice_partition_dedup)]
#![feature(control_flow_enum)]
+#![feature(hash_drain_filter)]
#![recursion_limit = "256"]
-#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
#[macro_use]
extern crate tracing;
}
}
- match fulfill_cx.select_all_or_error(infcx) {
- Ok(()) => true,
- Err(errors) => {
- infcx.report_fulfillment_errors(&errors, None, false);
+ match fulfill_cx.select_all_or_error(infcx).as_slice() {
+ [] => true,
+ errors => {
+ infcx.report_fulfillment_errors(errors, None, false);
false
}
}
term_id,
cause,
);
- if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(&err, None, false);
+ let errors = fulfillment_cx.select_all_or_error(&infcx);
+ if !errors.is_empty() {
+ infcx.report_fulfillment_errors(&errors, None, false);
error = true;
}
});
// variables. Process these constraints.
let mut fulfill_cx = FulfillmentContext::new();
fulfill_cx.register_predicate_obligations(self, result.obligations);
- if fulfill_cx.select_all_or_error(self).is_err() {
+ let errors = fulfill_cx.select_all_or_error(self);
+ if !errors.is_empty() {
self.tcx.sess.delay_span_bug(
span,
"implied_outlives_bounds failed to solve obligations from instantiation",
hir::TyKind::Path(hir::QPath::Resolved(
None,
hir::Path { res: hir::def::Res::Def(_, id), .. },
- )) if *id == def_id => true,
+ )) => *id == def_id,
_ => false,
})
})
let mut c = 0;
for i in 0..BENCH_RANGE_SIZE {
for j in i + 1..BENCH_RANGE_SIZE {
- black_box(map.range(f(i, j)));
+ let _ = black_box(map.range(f(i, j)));
c += 1;
}
}
let map: BTreeMap<_, _> = (0..size).map(|i| (i, i)).collect();
b.iter(|| {
for _ in 0..repeats {
- black_box(map.iter());
+ let _ = black_box(map.iter());
}
});
}
/// }
/// ```
#[stable(feature = "global_alloc", since = "1.28.0")]
+#[must_use = "losing the pointer will leak memory"]
#[inline]
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
unsafe { __rust_alloc(layout.size(), layout.align()) }
///
/// See [`GlobalAlloc::realloc`].
#[stable(feature = "global_alloc", since = "1.28.0")]
+#[must_use = "losing the pointer will leak memory"]
#[inline]
pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
/// }
/// ```
#[stable(feature = "global_alloc", since = "1.28.0")]
+#[must_use = "losing the pointer will leak memory"]
#[inline]
pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) }
/// let vec = heap.into_sorted_vec();
/// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]);
/// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
pub fn into_sorted_vec(mut self) -> Vec<T> {
let mut end = self.len();
///
/// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), vec![5, 4]);
/// ```
- #[must_use = "`self` will be dropped if the result is not used"]
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
IntoIterSorted { inner: self }
/// # Time complexity
///
/// Cost is *O*(1) in the worst case.
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn peek(&self) -> Option<&T> {
self.data.get(0)
/// assert!(heap.capacity() >= 100);
/// heap.push(4);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn capacity(&self) -> usize {
self.data.capacity()
///
/// assert_eq!(heap.len(), 2);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
self.data.len()
///
/// assert!(!heap.is_empty());
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_empty(&self) -> bool {
self.len() == 0
/// documentation for more.
///
/// [`iter`]: BinaryHeap::iter
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
iter: slice::Iter<'a, T>,
}
}
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
#[derive(Clone, Debug)]
pub struct IntoIterSorted<T> {
/// performance on *small* nodes of elements which are cheap to compare. However in the future we
/// would like to further explore choosing the optimal search strategy based on the choice of B,
/// and possibly other factors. Using linear search, searching for a random element is expected
-/// to take O(B * log(n)) comparisons, which is generally worse than a BST. In practice,
+/// to take B * log(n) comparisons, which is generally worse than a BST. In practice,
/// however, performance is excellent.
///
/// It is a logic error for a key to be modified in such a way that the key's ordering relative to
/// documentation for more.
///
/// [`iter`]: BTreeMap::iter
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, K: 'a, V: 'a> {
range: LazyLeafRange<marker::Immut<'a>, K, V>,
_marker: PhantomData<&'a mut (K, V)>,
}
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "collection_debug", since = "1.17.0")]
impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IterMut<'_, K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// documentation for more.
///
/// [`keys`]: BTreeMap::keys
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Keys<'a, K: 'a, V: 'a> {
inner: Iter<'a, K, V>,
/// documentation for more.
///
/// [`values`]: BTreeMap::values
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Values<'a, K: 'a, V: 'a> {
inner: Iter<'a, K, V>,
/// documentation for more.
///
/// [`values_mut`]: BTreeMap::values_mut
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "map_values_mut", since = "1.10.0")]
pub struct ValuesMut<'a, K: 'a, V: 'a> {
inner: IterMut<'a, K, V>,
/// See its documentation for more.
///
/// [`into_keys`]: BTreeMap::into_keys
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub struct IntoKeys<K, V> {
inner: IntoIter<K, V>,
/// See its documentation for more.
///
/// [`into_values`]: BTreeMap::into_values
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub struct IntoValues<K, V> {
inner: IntoIter<K, V>,
/// documentation for more.
///
/// [`range`]: BTreeMap::range
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "btree_range", since = "1.17.0")]
pub struct Range<'a, K: 'a, V: 'a> {
inner: LeafRange<marker::Immut<'a>, K, V>,
/// documentation for more.
///
/// [`range_mut`]: BTreeMap::range_mut
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "btree_range", since = "1.17.0")]
pub struct RangeMut<'a, K: 'a, V: 'a> {
inner: LeafRange<marker::ValMut<'a>, K, V>,
/// assert_eq!(keys, [1, 2]);
/// ```
#[inline]
- #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub fn into_keys(self) -> IntoKeys<K, V> {
IntoKeys { inner: self.into_iter() }
/// assert_eq!(values, ["hello", "goodbye"]);
/// ```
#[inline]
- #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub fn into_values(self) -> IntoValues<K, V> {
IntoValues { inner: self.into_iter() }
/// a.insert(1, "a");
/// assert_eq!(a.len(), 1);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
pub const fn len(&self) -> usize {
/// a.insert(1, "a");
/// assert!(!a.is_empty());
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
pub const fn is_empty(&self) -> bool {
/// map.entry("poneyland").or_insert(12);
/// assert_eq!(map.entry("poneyland").key(), &"poneyland");
/// ```
+ #[must_use]
#[stable(feature = "map_entry_keys", since = "1.10.0")]
pub fn key(&self) -> &K {
self.handle.reborrow().into_kv().0
/// assert_eq!(o.get(), &12);
/// }
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get(&self) -> &V {
self.handle.reborrow().into_kv().1
#[should_panic]
fn test_range_equal_excluded() {
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
- map.range((Excluded(2), Excluded(2)));
+ let _ = map.range((Excluded(2), Excluded(2)));
}
#[test]
#[should_panic]
fn test_range_backwards_1() {
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
- map.range((Included(3), Included(2)));
+ let _ = map.range((Included(3), Included(2)));
}
#[test]
#[should_panic]
fn test_range_backwards_2() {
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
- map.range((Included(3), Excluded(2)));
+ let _ = map.range((Included(3), Excluded(2)));
}
#[test]
#[should_panic]
fn test_range_backwards_3() {
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
- map.range((Excluded(3), Included(2)));
+ let _ = map.range((Excluded(3), Included(2)));
}
#[test]
#[should_panic]
fn test_range_backwards_4() {
let map: BTreeMap<_, _> = (0..5).map(|i| (i, i)).collect();
- map.range((Excluded(3), Excluded(2)));
+ let _ = map.range((Excluded(3), Excluded(2)));
}
#[test]
// we cause a different panic than `test_range_backwards_1` does.
// A more refined `should_panic` would be welcome.
if Cyclic3::C < Cyclic3::A {
- map.range(Cyclic3::C..=Cyclic3::A);
+ let _ = map.range(Cyclic3::C..=Cyclic3::A);
}
}
}
let map = (0..12).map(|i| (CompositeKey(i, EvilTwin(i)), ())).collect::<BTreeMap<_, _>>();
- map.range(EvilTwin(5)..=EvilTwin(7));
+ let _ = map.range(EvilTwin(5)..=EvilTwin(7));
}
#[test]
#[allow(dead_code)]
fn get<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) {
- v.get(t);
+ let _ = v.get(t);
}
#[allow(dead_code)]
fn get_mut<T: Ord>(v: &mut BTreeMap<Box<T>, ()>, t: &T) {
- v.get_mut(t);
+ let _ = v.get_mut(t);
}
#[allow(dead_code)]
fn get_key_value<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) {
- v.get_key_value(t);
+ let _ = v.get_key_value(t);
}
#[allow(dead_code)]
fn contains_key<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: &T) {
- v.contains_key(t);
+ let _ = v.contains_key(t);
}
#[allow(dead_code)]
fn range<T: Ord>(v: &BTreeMap<Box<T>, ()>, t: T) {
- v.range(t..);
+ let _ = v.range(t..);
}
#[allow(dead_code)]
fn range_mut<T: Ord>(v: &mut BTreeMap<Box<T>, ()>, t: T) {
- v.range_mut(t..);
+ let _ = v.range_mut(t..);
}
#[allow(dead_code)]
/// See its documentation for more.
///
/// [`iter`]: BTreeSet::iter
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
iter: Keys<'a, T, ()>,
/// See its documentation for more.
///
/// [`range`]: BTreeSet::range
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Debug)]
#[stable(feature = "btree_range", since = "1.17.0")]
pub struct Range<'a, T: 'a> {
/// See its documentation for more.
///
/// [`difference`]: BTreeSet::difference
+#[must_use = "this returns the difference as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Difference<'a, T: 'a> {
inner: DifferenceInner<'a, T>,
/// [`BTreeSet`]. See its documentation for more.
///
/// [`symmetric_difference`]: BTreeSet::symmetric_difference
+#[must_use = "this returns the difference as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SymmetricDifference<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
/// See its documentation for more.
///
/// [`intersection`]: BTreeSet::intersection
+#[must_use = "this returns the intersection as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Intersection<'a, T: 'a> {
inner: IntersectionInner<'a, T>,
/// See its documentation for more.
///
/// [`union`]: BTreeSet::union
+#[must_use = "this returns the union as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Union<'a, T: 'a>(MergeIterInner<Iter<'a, T>>);
/// set.insert(2);
/// assert_eq!(set.first(), Some(&1));
/// ```
+ #[must_use]
#[unstable(feature = "map_first_last", issue = "62924")]
pub fn first(&self) -> Option<&T>
where
/// set.insert(2);
/// assert_eq!(set.last(), Some(&2));
/// ```
+ #[must_use]
#[unstable(feature = "map_first_last", issue = "62924")]
pub fn last(&self) -> Option<&T>
where
/// v.insert(1);
/// assert_eq!(v.len(), 1);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
pub const fn len(&self) -> usize {
/// v.insert(1);
/// assert!(!v.is_empty());
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_btree_new", issue = "71835")]
pub const fn is_empty(&self) -> bool {
#[test]
fn test_ord_absence() {
fn set<K>(mut set: BTreeSet<K>) {
- set.is_empty();
- set.len();
+ let _ = set.is_empty();
+ let _ = set.len();
set.clear();
- set.iter();
- set.into_iter();
+ let _ = set.iter();
+ let _ = set.into_iter();
}
fn set_debug<K: Debug>(set: BTreeSet<K>) {
///
/// This `struct` is created by [`LinkedList::iter()`]. See its
/// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a, T: 'a> {
head: Option<NonNull<Node<T>>>,
///
/// This `struct` is created by [`LinkedList::iter_mut()`]. See its
/// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IterMut<'a, T: 'a> {
head: Option<NonNull<Node<T>>>,
///
/// The cursor is pointing to the "ghost" non-element if the list is empty.
#[inline]
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_front(&self) -> Cursor<'_, T> {
Cursor { index: 0, current: self.head, list: self }
///
/// The cursor is pointing to the "ghost" non-element if the list is empty.
#[inline]
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_front_mut(&mut self) -> CursorMut<'_, T> {
CursorMut { index: 0, current: self.head, list: self }
///
/// The cursor is pointing to the "ghost" non-element if the list is empty.
#[inline]
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_back(&self) -> Cursor<'_, T> {
Cursor { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }
///
/// The cursor is pointing to the "ghost" non-element if the list is empty.
#[inline]
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn cursor_back_mut(&mut self) -> CursorMut<'_, T> {
CursorMut { index: self.len.checked_sub(1).unwrap_or(0), current: self.tail, list: self }
/// assert!(!dl.is_empty());
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_empty(&self) -> bool {
self.head.is_none()
/// assert_eq!(dl.len(), 3);
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
self.len
/// assert_eq!(dl.front(), Some(&1));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn front(&self) -> Option<&T> {
unsafe { self.head.as_ref().map(|node| &node.as_ref().element) }
/// assert_eq!(dl.front(), Some(&5));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn front_mut(&mut self) -> Option<&mut T> {
unsafe { self.head.as_mut().map(|node| &mut node.as_mut().element) }
/// assert_eq!(dl.back(), Some(&1));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn back(&self) -> Option<&T> {
unsafe { self.tail.as_ref().map(|node| &node.as_ref().element) }
///
/// This returns `None` if the cursor is currently pointing to the
/// "ghost" non-element.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn index(&self) -> Option<usize> {
let _ = self.current?;
///
/// This returns `None` if the cursor is currently pointing to the
/// "ghost" non-element.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn current(&self) -> Option<&'a T> {
unsafe { self.current.map(|current| &(*current.as_ptr()).element) }
/// If the cursor is pointing to the "ghost" non-element then this returns
/// the first element of the `LinkedList`. If it is pointing to the last
/// element of the `LinkedList` then this returns `None`.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn peek_next(&self) -> Option<&'a T> {
unsafe {
/// If the cursor is pointing to the "ghost" non-element then this returns
/// the last element of the `LinkedList`. If it is pointing to the first
/// element of the `LinkedList` then this returns `None`.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn peek_prev(&self) -> Option<&'a T> {
unsafe {
/// Provides a reference to the front element of the cursor's parent list,
/// or None if the list is empty.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn front(&self) -> Option<&'a T> {
self.list.front()
/// Provides a reference to the back element of the cursor's parent list,
/// or None if the list is empty.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn back(&self) -> Option<&'a T> {
self.list.back()
///
/// This returns `None` if the cursor is currently pointing to the
/// "ghost" non-element.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn index(&self) -> Option<usize> {
let _ = self.current?;
///
/// This returns `None` if the cursor is currently pointing to the
/// "ghost" non-element.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn current(&mut self) -> Option<&mut T> {
unsafe { self.current.map(|current| &mut (*current.as_ptr()).element) }
/// Provides a reference to the front element of the cursor's parent list,
/// or None if the list is empty.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn front(&self) -> Option<&T> {
self.list.front()
/// Provides a mutable reference to the front element of the cursor's
/// parent list, or None if the list is empty.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn front_mut(&mut self) -> Option<&mut T> {
self.list.front_mut()
/// Provides a reference to the back element of the cursor's parent list,
/// or None if the list is empty.
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn back(&self) -> Option<&T> {
self.list.back()
/// assert_eq!(contents.next(), Some(0));
/// assert_eq!(contents.next(), None);
/// ```
+ #[must_use]
#[unstable(feature = "linked_list_cursors", issue = "58533")]
pub fn back_mut(&mut self) -> Option<&mut T> {
self.list.back_mut()
impl TryReserveError {
/// Details about the allocation that caused the error
#[inline]
+ #[must_use]
#[unstable(
feature = "try_reserve_kind",
reason = "Uncertain how much info should be exposed",
/// [`format_args!`]: core::format_args
/// [`format!`]: crate::format
#[cfg(not(no_global_oom_handling))]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn format(args: Arguments<'_>) -> string::String {
let capacity = args.estimated_capacity();
#![feature(extend_one)]
#![feature(fmt_internals)]
#![feature(fn_traits)]
+#![feature(inherent_ascii_escape)]
#![feature(inplace_iteration)]
#![feature(iter_advance_by)]
#![feature(iter_zip)]
#![feature(maybe_uninit_slice)]
#![cfg_attr(test, feature(new_uninit))]
#![feature(nonnull_slice_from_raw_parts)]
-#![feature(option_result_unwrap_unchecked)]
#![feature(pattern)]
#![feature(ptr_internals)]
#![feature(receiver_trait)]
//
// Rustdoc features:
#![feature(doc_cfg)]
-#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))]
+#![feature(doc_cfg_hide)]
// Technically, this is a bug in rustdoc: rustdoc sees the documentation on `#[lang = slice_alloc]`
// blocks is for `&[T]`, which also has documentation using this feature in `core`, and gets mad
// that the feature-gate isn't enabled. Ideally, it wouldn't check for the feature gate for docs
//! use std::rc::Rc;
//!
//! let my_rc = Rc::new(());
-//! Rc::downgrade(&my_rc);
+//! let my_weak = Rc::downgrade(&my_rc);
//! ```
//!
//! `Rc<T>`'s implementations of traits like `Clone` may also be called using
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !marker::Send for Rc<T> {}
+
+// Note that this negative impl isn't strictly necessary for correctness,
+// as `Rc` transitively contains a `Cell`, which is itself `!Sync`.
+// However, given how important `Rc`'s `!Sync`-ness is,
+// having an explicit negative impl is nice for documentation purposes
+// and results in nicer error messages.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !marker::Sync for Rc<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {}
+#[stable(feature = "rc_ref_unwind_safe", since = "1.58.0")]
+impl<T: RefUnwindSafe + ?Sized> RefUnwindSafe for Rc<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
///
/// let weak_five = Rc::downgrade(&five);
/// ```
+ #[must_use = "this returns a new `Weak` pointer, \
+ without modifying the original `Rc`"]
#[stable(feature = "rc_weak", since = "1.4.0")]
pub fn downgrade(this: &Self) -> Weak<T> {
this.inner().inc_weak();
/// Gets the number of strong (`Rc`) pointers pointing to this allocation.
///
/// If `self` was created using [`Weak::new`], this will return 0.
+ #[must_use]
#[stable(feature = "weak_counts", since = "1.41.0")]
pub fn strong_count(&self) -> usize {
if let Some(inner) = self.inner() { inner.strong() } else { 0 }
/// Gets the number of `Weak` pointers pointing to this allocation.
///
/// If no strong pointers remain, this will return zero.
+ #[must_use]
#[stable(feature = "weak_counts", since = "1.41.0")]
pub fn weak_count(&self) -> usize {
self.inner()
/// assert!(!first.ptr_eq(&third));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "weak_ptr_eq", since = "1.39.0")]
pub fn ptr_eq(&self, other: &Self) -> bool {
self.ptr.as_ptr() == other.ptr.as_ptr()
pub use core::slice::ArrayChunksMut;
#[unstable(feature = "array_windows", issue = "75027")]
pub use core::slice::ArrayWindows;
+#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+pub use core::slice::EscapeAscii;
#[stable(feature = "slice_get_slice", since = "1.28.0")]
pub use core::slice::SliceIndex;
#[stable(feature = "from_ref", since = "1.28.0")]
pub use core::slice::{RSplit, RSplitMut};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut};
+#[stable(feature = "split_inclusive", since = "1.51.0")]
+pub use core::slice::{SplitInclusive, SplitInclusiveMut};
////////////////////////////////////////////////////////////////////////////////
// Basic slice extension methods
pub use core::str::EncodeUtf16;
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
pub use core::str::SplitAsciiWhitespace;
-#[stable(feature = "split_inclusive", since = "1.53.0")]
+#[stable(feature = "split_inclusive", since = "1.51.0")]
pub use core::str::SplitInclusive;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::str::SplitWhitespace;
/// assert_eq!(*boxed_bytes, *s.as_bytes());
/// ```
#[stable(feature = "str_box_extras", since = "1.20.0")]
+ #[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub fn into_boxed_bytes(self: Box<str>) -> Box<[u8]> {
self.into()
/// assert_eq!(boxed_str.into_string(), string);
/// ```
#[stable(feature = "box_str", since = "1.4.0")]
+ #[must_use = "`self` will be dropped if the result is not used"]
#[inline]
pub fn into_string(self: Box<str>) -> String {
let slice = Box::<[u8]>::from(self);
///
/// ```should_panic
/// // this will panic at runtime
- /// "0123456789abcdef".repeat(usize::MAX);
+ /// let huge = "0123456789abcdef".repeat(usize::MAX);
/// ```
#[cfg(not(no_global_oom_handling))]
+ #[must_use]
#[stable(feature = "repeat_str", since = "1.16.0")]
pub fn repeat(&self, n: usize) -> String {
unsafe { String::from_utf8_unchecked(self.as_bytes().repeat(n)) }
///
/// assert_eq!("Hello �World", output);
/// ```
+ #[must_use]
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_utf8_lossy(v: &[u8]) -> Cow<'_, str> {
/// String::from_utf16_lossy(v));
/// ```
#[cfg(not(no_global_oom_handling))]
+ #[must_use]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_utf16_lossy(v: &[u16]) -> String {
/// assert!(s.capacity() >= 10);
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn capacity(&self) -> usize {
self.vec.capacity()
///
/// # Safety
///
- /// This function is unsafe because it does not check that the bytes passed
- /// to it are valid UTF-8. If this constraint is violated, it may cause
- /// memory unsafety issues with future users of the `String`, as the rest of
- /// the standard library assumes that `String`s are valid UTF-8.
+ /// This function is unsafe because the returned `&mut Vec` allows writing
+ /// bytes which are not valid UTF-8. If this constraint is violated, using
+ /// the original `String` after dropping the `&mut Vec` may violate memory
+ /// safety, as the rest of the standard library assumes that `String`s are
+ /// valid UTF-8.
///
/// # Examples
///
/// assert_eq!(fancy_f.chars().count(), 3);
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> usize {
self.vec.len()
/// assert!(!v.is_empty());
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_empty(&self) -> bool {
self.len() == 0
/// // the first byte is invalid here
/// assert_eq!(1, error.valid_up_to());
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn utf8_error(&self) -> Utf8Error {
self.error
/// let x_ptr = Arc::into_raw(x);
/// assert_eq!(unsafe { &*x_ptr }, "hello");
/// ```
+ #[must_use = "losing the pointer will leak memory"]
#[stable(feature = "rc_raw", since = "1.17.0")]
pub fn into_raw(this: Self) -> *const T {
let ptr = Self::as_ptr(&this);
/// assert_eq!(1, Arc::weak_count(&five));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "arc_counts", since = "1.15.0")]
pub fn weak_count(this: &Self) -> usize {
let cnt = this.inner().weak.load(SeqCst);
/// assert_eq!(2, Arc::strong_count(&five));
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "arc_counts", since = "1.15.0")]
pub fn strong_count(this: &Self) -> usize {
this.inner().strong.load(SeqCst)
drop(Weak { ptr: self.ptr });
}
- #[inline]
- #[stable(feature = "ptr_eq", since = "1.17.0")]
/// Returns `true` if the two `Arc`s point to the same allocation
/// (in a vein similar to [`ptr::eq`]).
///
/// ```
///
/// [`ptr::eq`]: core::ptr::eq "ptr::eq"
+ #[inline]
+ #[must_use]
+ #[stable(feature = "ptr_eq", since = "1.17.0")]
pub fn ptr_eq(this: &Self, other: &Self) -> bool {
this.ptr.as_ptr() == other.ptr.as_ptr()
}
/// Gets the number of strong (`Arc`) pointers pointing to this allocation.
///
/// If `self` was created using [`Weak::new`], this will return 0.
+ #[must_use]
#[stable(feature = "weak_counts", since = "1.41.0")]
pub fn strong_count(&self) -> usize {
if let Some(inner) = self.inner() { inner.strong.load(SeqCst) } else { 0 }
/// Due to implementation details, the returned value can be off by 1 in
/// either direction when other threads are manipulating any `Arc`s or
/// `Weak`s pointing to the same allocation.
+ #[must_use]
#[stable(feature = "weak_counts", since = "1.41.0")]
pub fn weak_count(&self) -> usize {
self.inner()
///
/// [`ptr::eq`]: core::ptr::eq "ptr::eq"
#[inline]
+ #[must_use]
#[stable(feature = "weak_ptr_eq", since = "1.39.0")]
pub fn ptr_eq(&self, other: &Self) -> bool {
self.ptr.as_ptr() == other.ptr.as_ptr()
/// Returns a reference to the underlying allocator.
#[unstable(feature = "allocator_api", issue = "32838")]
+ #[must_use]
#[inline]
pub fn allocator(&self) -> &A {
unsafe { self.vec.as_ref().allocator() }
#[should_panic]
fn test_split_at_boundscheck() {
let s = "ศไทย中华Việt Nam";
- s.split_at(1);
+ let _ = s.split_at(1);
}
#[test]
-Subproject commit 7f14f76c8ba6945c052fab77022e6e768b58e0b4
+Subproject commit b02ed04a7e915659eea6fb1607df469b84a30638
/// The minimum size in bytes for a memory block of this layout.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.50.0")]
+ #[must_use]
#[inline]
pub const fn size(&self) -> usize {
self.size_
/// allocate backing structure for `T` (which could be a trait
/// or other unsized type like a slice).
#[stable(feature = "alloc_layout", since = "1.28.0")]
+ #[must_use]
#[inline]
pub fn for_value<T: ?Sized>(t: &T) -> Self {
let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
/// [trait object]: ../../book/ch17-02-trait-objects.html
/// [extern type]: ../../unstable-book/language-features/extern-types.html
#[unstable(feature = "layout_for_ptr", issue = "69835")]
+ #[must_use]
pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
// SAFETY: we pass along the prerequisites of these functions to the caller
let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) };
/// some other means.
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[rustc_const_unstable(feature = "alloc_layout_extra", issue = "55724")]
+ #[must_use]
#[inline]
pub const fn dangling(&self) -> NonNull<u8> {
// SAFETY: align is guaranteed to be non-zero
/// assert_eq!(is_string(&0), false);
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_type_id", issue = "77125")]
pub const fn of<T: ?Sized + 'static>() -> TypeId {
/// "core::option::Option<alloc::string::String>",
/// );
/// ```
+#[must_use]
#[stable(feature = "type_name", since = "1.38.0")]
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
pub const fn type_name<T: ?Sized>() -> &'static str {
/// let y = 1.0;
/// println!("{}", type_name_of_val(&y));
/// ```
+#[must_use]
#[unstable(feature = "type_name_of_val", issue = "66359")]
#[rustc_const_unstable(feature = "const_type_name", issue = "63084")]
pub const fn type_name_of_val<T: ?Sized>(_val: &T) -> &'static str {
///
/// This `struct` is created by the [`escape_default`] function. See its
/// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
pub struct EscapeDefault {
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<T: ?Sized> Send for Cell<T> where T: Send {}
+// Note that this negative impl isn't strictly necessary for correctness,
+// as `Cell` wraps `UnsafeCell`, which is itself `!Sync`.
+// However, given how important `Cell`'s `!Sync`-ness is,
+// having an explicit negative impl is nice for documentation purposes
+// and results in nicer error messages.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Sync for Cell<T> {}
/// with the widespread use of `r.borrow().clone()` to clone the contents of
/// a `RefCell`.
#[stable(feature = "cell_extras", since = "1.15.0")]
+ #[must_use]
#[inline]
pub fn clone(orig: &Ref<'b, T>) -> Ref<'b, T> {
Ref { value: orig.value, borrow: orig.borrow.clone() }
impl DecodeUtf16Error {
/// Returns the unpaired surrogate which caused this error.
+ #[must_use]
#[stable(feature = "decode_utf16", since = "1.9.0")]
pub fn unpaired_surrogate(&self) -> u16 {
self.code
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "clone"]
#[rustc_diagnostic_item = "Clone"]
-#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
+#[rustc_trivial_field_reads]
pub trait Clone: Sized {
/// Returns a copy of the value.
///
/// }
/// ```
#[unstable(feature = "default_free_fn", issue = "73014")]
+#[must_use]
#[inline]
pub fn default<T: Default>() -> T {
Default::default()
/// valid index of `args`.
/// 3. Every [`Count::Param`] within `fmt` must contain a valid index of
/// `args`.
- #[cfg(not(bootstrap))]
#[doc(hidden)]
#[inline]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
Arguments { pieces, fmt: Some(fmt), args }
}
- #[cfg(bootstrap)]
- #[doc(hidden)]
- #[inline]
- #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
- #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
- pub const unsafe fn new_v1_formatted(
- pieces: &'a [&'static str],
- args: &'a [ArgumentV1<'a>],
- fmt: &'a [rt::v1::Argument],
- ) -> Arguments<'a> {
- Arguments { pieces, fmt: Some(fmt), args }
- }
-
/// Estimates the length of the formatted text.
///
/// This is intended to be used for setting initial `String` capacity
)]
#[doc(alias = "{:?}")]
#[rustc_diagnostic_item = "Debug"]
-#[cfg_attr(not(bootstrap), rustc_trivial_field_reads)]
+#[rustc_trivial_field_reads]
pub trait Debug {
/// Formats the value using the given formatter.
///
}
/// Flags for formatting
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(
since = "1.24.0",
/// assert_eq!(&format!("{:G>3}", Foo), "GGG");
/// assert_eq!(&format!("{:t>6}", Foo), "tttttt");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn fill(&self) -> char {
self.fill
/// assert_eq!(&format!("{:^}", Foo), "center");
/// assert_eq!(&format!("{}", Foo), "into the void");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags_align", since = "1.28.0")]
pub fn align(&self) -> Option<Alignment> {
match self.align {
/// assert_eq!(&format!("{:10}", Foo(23)), "Foo(23) ");
/// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn width(&self) -> Option<usize> {
self.width
/// assert_eq!(&format!("{:.4}", Foo(23.2)), "Foo(23.2000)");
/// assert_eq!(&format!("{}", Foo(23.2)), "Foo(23.20)");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn precision(&self) -> Option<usize> {
self.precision
/// assert_eq!(&format!("{:+}", Foo(23)), "Foo(+23)");
/// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_plus(&self) -> bool {
self.flags & (1 << FlagV1::SignPlus as u32) != 0
/// assert_eq!(&format!("{:-}", Foo(23)), "-Foo(23)");
/// assert_eq!(&format!("{}", Foo(23)), "Foo(23)");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_minus(&self) -> bool {
self.flags & (1 << FlagV1::SignMinus as u32) != 0
/// assert_eq!(&format!("{:#}", Foo(23)), "Foo(23)");
/// assert_eq!(&format!("{}", Foo(23)), "23");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn alternate(&self) -> bool {
self.flags & (1 << FlagV1::Alternate as u32) != 0
///
/// assert_eq!(&format!("{:04}", Foo(23)), "23");
/// ```
+ #[must_use]
#[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn sign_aware_zero_pad(&self) -> bool {
self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0
#[lang = "get_context"]
#[doc(hidden)]
#[unstable(feature = "gen_future", issue = "50547")]
+#[must_use]
#[inline]
pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> {
// SAFETY: the caller must guarantee that `cx.0` is a valid pointer
forward_ref_unop!(impl $imp, $method for $t,
#[stable(feature = "rust1", since = "1.0.0")]);
};
+ (impl const $imp:ident, $method:ident for $t:ty) => {
+ forward_ref_unop!(impl const $imp, $method for $t,
+ #[stable(feature = "rust1", since = "1.0.0")]);
+ };
+ // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
+ (impl const $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
+ #[$attr]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const $imp for &$t {
+ type Output = <$t as $imp>::Output;
+
+ #[inline]
+ fn $method(self) -> <$t as $imp>::Output {
+ $imp::$method(*self)
+ }
+ }
+ };
(impl $imp:ident, $method:ident for $t:ty, #[$attr:meta]) => {
#[$attr]
impl $imp for &$t {
forward_ref_binop!(impl $imp, $method for $t, $u,
#[stable(feature = "rust1", since = "1.0.0")]);
};
+ (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
+ forward_ref_binop!(impl const $imp, $method for $t, $u,
+ #[stable(feature = "rust1", since = "1.0.0")]);
+ };
+ // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
+ (impl const $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
+ #[$attr]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl<'a> const $imp<$u> for &'a $t {
+ type Output = <$t as $imp<$u>>::Output;
+
+ #[inline]
+ fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
+ $imp::$method(*self, other)
+ }
+ }
+
+ #[$attr]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const $imp<&$u> for $t {
+ type Output = <$t as $imp<$u>>::Output;
+
+ #[inline]
+ fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
+ $imp::$method(self, *other)
+ }
+ }
+
+ #[$attr]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const $imp<&$u> for &$t {
+ type Output = <$t as $imp<$u>>::Output;
+
+ #[inline]
+ fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
+ $imp::$method(*self, *other)
+ }
+ }
+ };
(impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
#[$attr]
impl<'a> $imp<$u> for &'a $t {
forward_ref_op_assign!(impl $imp, $method for $t, $u,
#[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
};
+ (impl const $imp:ident, $method:ident for $t:ty, $u:ty) => {
+ forward_ref_op_assign!(impl const $imp, $method for $t, $u,
+ #[stable(feature = "op_assign_builtins_by_ref", since = "1.22.0")]);
+ };
+ // Equivalent to the non-const version, with the addition of `rustc_const_unstable`
+ (impl const $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
+ #[$attr]
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const $imp<&$u> for $t {
+ #[inline]
+ fn $method(&mut self, other: &$u) {
+ $imp::$method(self, *other);
+ }
+ }
+ };
(impl $imp:ident, $method:ident for $t:ty, $u:ty, #[$attr:meta]) => {
#[$attr]
impl $imp<&$u> for $t {
/// or have any other observable side-effects, the behavior is undefined.
///
/// [referential transparency]: https://en.wikipedia.org/wiki/Referential_transparency
-#[cfg(not(bootstrap))]
#[unstable(
feature = "const_eval_select",
issue = "none",
called_at_rt.call_once(arg)
}
-#[cfg(not(bootstrap))]
#[unstable(
feature = "const_eval_select",
issue = "none",
/// An iterator that yields nothing.
///
/// This `struct` is created by the [`empty()`] function. See its documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "iter_empty", since = "1.2.0")]
pub struct Empty<T>(marker::PhantomData<T>);
#![feature(const_caller_location)]
#![feature(const_cell_into_inner)]
#![feature(const_discriminant)]
+#![cfg_attr(not(bootstrap), feature(const_eval_select))]
#![feature(const_float_bits_conv)]
#![feature(const_float_classify)]
+#![feature(const_fmt_arguments_new)]
#![feature(const_heap)]
#![feature(const_inherent_unchecked_arith)]
#![feature(const_int_unchecked_arith)]
#![feature(const_maybe_uninit_as_ptr)]
#![feature(const_maybe_uninit_assume_init)]
#![feature(const_num_from_num)]
+#![feature(const_ops)]
#![feature(const_option)]
#![feature(const_pin)]
#![feature(const_replace)]
#![feature(const_fn_trait_bound)]
#![feature(const_impl_trait)]
#![feature(const_mut_refs)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(const_precise_live_drops)]
#![feature(const_raw_ptr_deref)]
#![feature(const_refs_to_cell)]
#![feature(doc_notable_trait)]
#![feature(doc_primitive)]
#![feature(exhaustive_patterns)]
-#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))]
+#![feature(doc_cfg_hide)]
#![feature(extern_types)]
#![feature(fundamental)]
#![feature(if_let_guard)]
#![feature(llvm_asm)]
#![feature(min_specialization)]
#![feature(mixed_integer_ops)]
-#![cfg_attr(not(bootstrap), feature(must_not_suspend))]
+#![feature(must_not_suspend)]
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(no_core)]
#![feature(try_blocks)]
#![feature(unboxed_closures)]
#![feature(unsized_fn_params)]
+#![cfg_attr(not(bootstrap), feature(asm_const))]
//
// Target features:
#![feature(aarch64_target_feature)]
/// [arc]: ../../std/sync/struct.Arc.html
/// [ub]: ../../reference/behavior-considered-undefined.html
#[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(all(not(test), bootstrap), rustc_diagnostic_item = "send_trait")]
-#[cfg_attr(all(not(test), not(bootstrap)), rustc_diagnostic_item = "Send")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "Send")]
#[rustc_on_unimplemented(
message = "`{Self}` cannot be sent between threads safely",
label = "`{Self}` cannot be sent between threads safely"
///
/// [alignment]: align_of
#[inline(always)]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_size_of", since = "1.24.0")]
/// assert_eq!(13, mem::size_of_val(y));
/// ```
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")]
#[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of_val")]
/// assert_eq!(13, unsafe { mem::size_of_val_raw(y) });
/// ```
#[inline]
+#[must_use]
#[unstable(feature = "layout_for_ptr", issue = "69835")]
#[rustc_const_unstable(feature = "const_size_of_val_raw", issue = "46571")]
pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
/// assert_eq!(4, mem::min_align_of::<i32>());
/// ```
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(reason = "use `align_of` instead", since = "1.2.0")]
pub fn min_align_of<T>() -> usize {
/// assert_eq!(4, mem::min_align_of_val(&5i32));
/// ```
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(reason = "use `align_of_val` instead", since = "1.2.0")]
pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
/// assert_eq!(4, mem::align_of::<i32>());
/// ```
#[inline(always)]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_align_of", since = "1.24.0")]
/// assert_eq!(4, mem::align_of_val(&5i32));
/// ```
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_align_of_val", issue = "46571")]
#[allow(deprecated)]
/// assert_eq!(4, unsafe { mem::align_of_val_raw(&5i32) });
/// ```
#[inline]
+#[must_use]
#[unstable(feature = "layout_for_ptr", issue = "69835")]
#[rustc_const_unstable(feature = "const_align_of_val_raw", issue = "46571")]
pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
/// }
/// ```
#[inline]
+#[must_use]
#[stable(feature = "needs_drop", since = "1.21.0")]
#[rustc_const_stable(feature = "const_needs_drop", since = "1.36.0")]
#[rustc_diagnostic_item = "needs_drop"]
/// let _y: fn() = unsafe { mem::zeroed() }; // And again!
/// ```
#[inline(always)]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated_in_future)]
#[allow(deprecated)]
/// [assume_init]: MaybeUninit::assume_init
/// [inv]: MaybeUninit#initialization-invariant
#[inline(always)]
+#[must_use]
#[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated_in_future)]
/// assert_eq!(foo_array, [10]);
/// ```
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")]
pub const unsafe fn transmute_copy<T, U>(src: &T) -> U {
/// assert_eq!(mem::variant_count::<Result<!, !>>(), 2);
/// ```
#[inline(always)]
+#[must_use]
#[unstable(feature = "variant_count", issue = "73662")]
#[rustc_const_unstable(feature = "variant_count", issue = "73662")]
#[rustc_diagnostic_item = "mem_variant_count"]
impl ParseIntError {
/// Outputs the detailed cause of parsing an integer failing.
+ #[must_use]
#[stable(feature = "int_error_matching", since = "1.55.0")]
pub fn kind(&self) -> &IntErrorKind {
&self.kind
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
/// ```
#[unstable(feature = "total_cmp", issue = "72599")]
+ #[must_use]
#[inline]
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
let mut left = self.to_bits() as i32;
/// # .all(|(a, b)| a.to_bits() == b.to_bits()))
/// ```
#[unstable(feature = "total_cmp", issue = "72599")]
+ #[must_use]
#[inline]
pub fn total_cmp(&self, other: &Self) -> crate::cmp::Ordering {
let mut left = self.to_bits() as i64;
without modifying the original"]
#[inline]
pub const fn checked_div(self, rhs: Self) -> Option<Self> {
- // Using `&` helps LLVM see that it is the same check made in division.
- if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
+ if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
None
} else {
// SAFETY: div by zero and by INT_MIN have been checked above
without modifying the original"]
#[inline]
pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
- // Using `&` helps LLVM see that it is the same check made in division.
- if unlikely!(rhs == 0 || ((self == Self::MIN) & (rhs == -1))) {
+ if unlikely!(rhs == 0 || ((self == Self::MIN) && (rhs == -1))) {
None
} else {
// SAFETY: div by zero and by INT_MIN have been checked above
}
macro_rules! widening_impl {
- ($SelfT:ty, $WideT:ty, $BITS:literal) => {
+ ($SelfT:ty, $WideT:ty, $BITS:literal, unsigned) => {
+ widening_impl!($SelfT, $WideT, $BITS, "");
+ };
+ ($SelfT:ty, $WideT:ty, $BITS:literal, signed) => {
+ widening_impl!($SelfT, $WideT, $BITS, "# //");
+ };
+ ($SelfT:ty, $WideT:ty, $BITS:literal, $AdaptiveTestPrefix:literal) => {
/// Calculates the complete product `self * rhs` without the possibility to overflow.
///
/// This returns the low-order (wrapping) bits and the high-order (overflow) bits
/// assert_eq!(5u32.carrying_mul(2, 10), (20, 0));
/// assert_eq!(1_000_000_000u32.carrying_mul(10, 0), (1410065408, 2));
/// assert_eq!(1_000_000_000u32.carrying_mul(10, 10), (1410065418, 2));
+ #[doc = concat!($AdaptiveTestPrefix, "assert_eq!(",
+ stringify!($SelfT), "::MAX.carrying_mul(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX), ",
+ "(0, ", stringify!($SelfT), "::MAX));"
+ )]
+ /// ```
+ ///
+ /// If `carry` is zero, this is similar to [`overflowing_mul`](Self::overflowing_mul),
+ /// except that it gives the value of the overflow instead of just whether one happened:
+ ///
+ /// ```
+ /// #![feature(bigint_helper_methods)]
+ /// let r = u8::carrying_mul(7, 13, 0);
+ /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(7, 13));
+ /// let r = u8::carrying_mul(13, 42, 0);
+ /// assert_eq!((r.0, r.1 != 0), u8::overflowing_mul(13, 42));
+ /// ```
+ ///
+ /// The value of the first field in the returned tuple matches what you'd get
+ /// by combining the [`wrapping_mul`](Self::wrapping_mul) and
+ /// [`wrapping_add`](Self::wrapping_add) methods:
+ ///
+ /// ```
+ /// #![feature(bigint_helper_methods)]
+ /// assert_eq!(
+ /// 789_u16.carrying_mul(456, 123).0,
+ /// 789_u16.wrapping_mul(456).wrapping_add(123),
+ /// );
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")]
#[lang = "i8"]
impl i8 {
- widening_impl! { i8, i16, 8 }
int_impl! { i8, i8, u8, 8, 7, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
"[0x12]", "[0x12]", "", "" }
+ widening_impl! { i8, i16, 8, signed }
}
#[lang = "i16"]
impl i16 {
- widening_impl! { i16, i32, 16 }
int_impl! { i16, i16, u16, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
"0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
+ widening_impl! { i16, i32, 16, signed }
}
#[lang = "i32"]
impl i32 {
- widening_impl! { i32, i64, 32 }
int_impl! { i32, i32, u32, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
"0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78]", "", "" }
+ widening_impl! { i32, i64, 32, signed }
}
#[lang = "i64"]
impl i64 {
- widening_impl! { i64, i128, 64 }
int_impl! { i64, i64, u64, 64, 63, -9223372036854775808, 9223372036854775807, 12,
"0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
"0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" }
+ widening_impl! { i64, i128, 64, signed }
}
#[lang = "i128"]
#[cfg(target_pointer_width = "16")]
#[lang = "isize"]
impl isize {
- widening_impl! { isize, i32, 16 }
int_impl! { isize, i16, usize, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234",
"0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { isize, i32, 16, signed }
}
#[cfg(target_pointer_width = "32")]
#[lang = "isize"]
impl isize {
- widening_impl! { isize, i64, 32 }
int_impl! { isize, i32, usize, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
"0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { isize, i64, 32, signed }
}
#[cfg(target_pointer_width = "64")]
#[lang = "isize"]
impl isize {
- widening_impl! { isize, i128, 64 }
int_impl! { isize, i64, usize, 64, 63, -9223372036854775808, 9223372036854775807,
12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
- "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
- usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
+ usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { isize, i128, 64, signed }
}
/// If 6th bit set ascii is upper case.
#[lang = "u8"]
impl u8 {
- widening_impl! { u8, u16, 8 }
uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
"[0x12]", "", "" }
+ widening_impl! { u8, u16, 8, unsigned }
/// Checks if the value is within the ASCII range.
///
#[lang = "u16"]
impl u16 {
- widening_impl! { u16, u32, 16 }
uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
"[0x34, 0x12]", "[0x12, 0x34]", "", "" }
+ widening_impl! { u16, u32, 16, unsigned }
}
#[lang = "u32"]
impl u32 {
- widening_impl! { u32, u64, 32 }
uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
+ widening_impl! { u32, u64, 32, unsigned }
}
#[lang = "u64"]
impl u64 {
- widening_impl! { u64, u128, 64 }
uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
"[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
"", ""}
+ widening_impl! { u64, u128, 64, unsigned }
}
#[lang = "u128"]
#[cfg(target_pointer_width = "16")]
#[lang = "usize"]
impl usize {
- widening_impl! { usize, u32, 16 }
uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
"[0x34, 0x12]", "[0x12, 0x34]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { usize, u32, 16, unsigned }
}
#[cfg(target_pointer_width = "32")]
#[lang = "usize"]
impl usize {
- widening_impl! { usize, u64, 32 }
uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
"0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { usize, u64, 32, unsigned }
}
#[cfg(target_pointer_width = "64")]
#[lang = "usize"]
impl usize {
- widening_impl! { usize, u128, 64 }
uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
"0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
"[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
- "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
+ "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+ widening_impl! { usize, u128, 64, unsigned }
}
/// A classification of floating point numbers.
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOr for $Ty {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOr for $Ty {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self::Output {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOr<$Int> for $Ty {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOr<$Int> for $Ty {
type Output = Self;
#[inline]
fn bitor(self, rhs: $Int) -> Self::Output {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOr<$Ty> for $Int {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOr<$Ty> for $Int {
type Output = $Ty;
#[inline]
fn bitor(self, rhs: $Ty) -> Self::Output {
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOrAssign for $Ty {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOrAssign for $Ty {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
*self = *self | rhs;
}
#[stable(feature = "nonzero_bitor", since = "1.45.0")]
- impl BitOrAssign<$Int> for $Ty {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOrAssign<$Int> for $Ty {
#[inline]
fn bitor_assign(&mut self, rhs: $Int) {
*self = *self | rhs;
( $( $Ty: ident($Int: ty); )+ ) => {
$(
#[stable(feature = "nonzero_div", since = "1.51.0")]
- impl Div<$Ty> for $Int {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Div<$Ty> for $Int {
type Output = $Int;
/// This operation rounds towards zero,
/// truncating any fractional part of the exact result, and cannot panic.
}
#[stable(feature = "nonzero_div", since = "1.51.0")]
- impl Rem<$Ty> for $Int {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Rem<$Ty> for $Int {
type Output = $Int;
/// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
#[inline]
/// additional bit of overflow. This allows for chaining together multiple additions
/// to create "big integers" which represent larger values.
///
+ #[doc = concat!("This can be thought of as a ", stringify!($BITS), "-bit \"full adder\", in the electronics sense.")]
+ ///
/// # Examples
///
/// Basic usage
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (0, true));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (0, true));")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (1, true));")]
+ #[doc = concat!("assert_eq!(",
+ stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ",
+ "(", stringify!($SelfT), "::MAX, true));"
+ )]
+ /// ```
+ ///
+ /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add):
+ ///
+ /// ```
+ /// #![feature(bigint_helper_methods)]
+ #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")]
+ #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")]
/// ```
#[unstable(feature = "bigint_helper_methods", issue = "85532")]
#[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
// to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
let (a, b) = self.overflowing_add(rhs);
let (c, d) = a.overflowing_add(carry as $SelfT);
- (c, b | d)
+ (c, b || d)
}
/// Calculates `self` + `rhs` with a signed `rhs`
// to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic
let (a, b) = self.overflowing_sub(rhs);
let (c, d) = a.overflowing_sub(borrow as $SelfT);
- (c, b | d)
+ (c, b || d)
}
/// Computes the absolute difference between `self` and `other`.
macro_rules! sh_impl_signed {
($t:ident, $f:ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shl<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shl<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
}
}
}
- forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
+ forward_ref_binop! { impl const Shl, shl for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShlAssign<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShlAssign<$f> for Wrapping<$t> {
#[inline]
fn shl_assign(&mut self, other: $f) {
*self = *self << other;
}
}
- forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl const ShlAssign, shl_assign for Wrapping<$t>, $f }
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shr<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shr<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
}
}
}
- forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
+ forward_ref_binop! { impl const Shr, shr for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShrAssign<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShrAssign<$f> for Wrapping<$t> {
#[inline]
fn shr_assign(&mut self, other: $f) {
*self = *self >> other;
}
}
- forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl const ShrAssign, shr_assign for Wrapping<$t>, $f }
};
}
macro_rules! sh_impl_unsigned {
($t:ident, $f:ident) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shl<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shl<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_shl((other & self::shift_max::$t as $f) as u32))
}
}
- forward_ref_binop! { impl Shl, shl for Wrapping<$t>, $f,
+ forward_ref_binop! { impl const Shl, shl for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShlAssign<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShlAssign<$f> for Wrapping<$t> {
#[inline]
fn shl_assign(&mut self, other: $f) {
*self = *self << other;
}
}
- forward_ref_op_assign! { impl ShlAssign, shl_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl const ShlAssign, shl_assign for Wrapping<$t>, $f }
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shr<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shr<$f> for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_shr((other & self::shift_max::$t as $f) as u32))
}
}
- forward_ref_binop! { impl Shr, shr for Wrapping<$t>, $f,
+ forward_ref_binop! { impl const Shr, shr for Wrapping<$t>, $f,
#[stable(feature = "wrapping_ref_ops", since = "1.39.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShrAssign<$f> for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShrAssign<$f> for Wrapping<$t> {
#[inline]
fn shr_assign(&mut self, other: $f) {
*self = *self >> other;
}
}
- forward_ref_op_assign! { impl ShrAssign, shr_assign for Wrapping<$t>, $f }
+ forward_ref_op_assign! { impl const ShrAssign, shr_assign for Wrapping<$t>, $f }
};
}
macro_rules! wrapping_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Add for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Add for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_add(other.0))
}
}
- forward_ref_binop! { impl Add, add for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const Add, add for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl AddAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const AddAssign for Wrapping<$t> {
#[inline]
fn add_assign(&mut self, other: Wrapping<$t>) {
*self = *self + other;
}
}
- forward_ref_op_assign! { impl AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "rust1", since = "1.0.0")]
- impl Sub for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Sub for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_sub(other.0))
}
}
- forward_ref_binop! { impl Sub, sub for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const Sub, sub for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl SubAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const SubAssign for Wrapping<$t> {
#[inline]
fn sub_assign(&mut self, other: Wrapping<$t>) {
*self = *self - other;
}
}
- forward_ref_op_assign! { impl SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "rust1", since = "1.0.0")]
- impl Mul for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Mul for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl MulAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const MulAssign for Wrapping<$t> {
#[inline]
fn mul_assign(&mut self, other: Wrapping<$t>) {
*self = *self * other;
}
}
- forward_ref_op_assign! { impl MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_div", since = "1.3.0")]
- impl Div for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Div for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_div(other.0))
}
}
- forward_ref_binop! { impl Div, div for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const Div, div for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl DivAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const DivAssign for Wrapping<$t> {
#[inline]
fn div_assign(&mut self, other: Wrapping<$t>) {
*self = *self / other;
}
}
- forward_ref_op_assign! { impl DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_impls", since = "1.7.0")]
- impl Rem for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Rem for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0.wrapping_rem(other.0))
}
}
- forward_ref_binop! { impl Rem, rem for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const Rem, rem for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl RemAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const RemAssign for Wrapping<$t> {
#[inline]
fn rem_assign(&mut self, other: Wrapping<$t>) {
*self = *self % other;
}
}
- forward_ref_op_assign! { impl RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "rust1", since = "1.0.0")]
- impl Not for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Not for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(!self.0)
}
}
- forward_ref_unop! { impl Not, not for Wrapping<$t>,
+ forward_ref_unop! { impl const Not, not for Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitXor for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitXor for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0 ^ other.0)
}
}
- forward_ref_binop! { impl BitXor, bitxor for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const BitXor, bitxor for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitXorAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitXorAssign for Wrapping<$t> {
#[inline]
fn bitxor_assign(&mut self, other: Wrapping<$t>) {
*self = *self ^ other;
}
}
- forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitOr for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOr for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0 | other.0)
}
}
- forward_ref_binop! { impl BitOr, bitor for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const BitOr, bitor for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitOrAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOrAssign for Wrapping<$t> {
#[inline]
fn bitor_assign(&mut self, other: Wrapping<$t>) {
*self = *self | other;
}
}
- forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitAnd for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitAnd for Wrapping<$t> {
type Output = Wrapping<$t>;
#[inline]
Wrapping(self.0 & other.0)
}
}
- forward_ref_binop! { impl BitAnd, bitand for Wrapping<$t>, Wrapping<$t>,
+ forward_ref_binop! { impl const BitAnd, bitand for Wrapping<$t>, Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitAndAssign for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitAndAssign for Wrapping<$t> {
#[inline]
fn bitand_assign(&mut self, other: Wrapping<$t>) {
*self = *self & other;
}
}
- forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
+ forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
#[stable(feature = "wrapping_neg", since = "1.10.0")]
- impl Neg for Wrapping<$t> {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Neg for Wrapping<$t> {
type Output = Self;
#[inline]
fn neg(self) -> Self {
Wrapping(0) - self
}
}
- forward_ref_unop! { impl Neg, neg for Wrapping<$t>,
+ forward_ref_unop! { impl const Neg, neg for Wrapping<$t>,
#[stable(feature = "wrapping_ref", since = "1.14.0")] }
)*)
macro_rules! add_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Add for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Add for $t {
type Output = $t;
#[inline]
fn add(self, other: $t) -> $t { self + other }
}
- forward_ref_binop! { impl Add, add for $t, $t }
+ forward_ref_binop! { impl const Add, add for $t, $t }
)*)
}
macro_rules! sub_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Sub for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Sub for $t {
type Output = $t;
#[inline]
fn sub(self, other: $t) -> $t { self - other }
}
- forward_ref_binop! { impl Sub, sub for $t, $t }
+ forward_ref_binop! { impl const Sub, sub for $t, $t }
)*)
}
macro_rules! mul_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Mul for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Mul for $t {
type Output = $t;
#[inline]
fn mul(self, other: $t) -> $t { self * other }
}
- forward_ref_binop! { impl Mul, mul for $t, $t }
+ forward_ref_binop! { impl const Mul, mul for $t, $t }
)*)
}
///
#[doc = $panic]
#[stable(feature = "rust1", since = "1.0.0")]
- impl Div for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Div for $t {
type Output = $t;
#[inline]
fn div(self, other: $t) -> $t { self / other }
}
- forward_ref_binop! { impl Div, div for $t, $t }
+ forward_ref_binop! { impl const Div, div for $t, $t }
)*)*)
}
macro_rules! div_impl_float {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Div for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Div for $t {
type Output = $t;
#[inline]
fn div(self, other: $t) -> $t { self / other }
}
- forward_ref_binop! { impl Div, div for $t, $t }
+ forward_ref_binop! { impl const Div, div for $t, $t }
)*)
}
///
#[doc = $panic]
#[stable(feature = "rust1", since = "1.0.0")]
- impl Rem for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Rem for $t {
type Output = $t;
#[inline]
fn rem(self, other: $t) -> $t { self % other }
}
- forward_ref_binop! { impl Rem, rem for $t, $t }
+ forward_ref_binop! { impl const Rem, rem for $t, $t }
)*)*)
}
/// assert_eq!(x % y, remainder);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
- impl Rem for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Rem for $t {
type Output = $t;
#[inline]
fn rem(self, other: $t) -> $t { self % other }
}
- forward_ref_binop! { impl Rem, rem for $t, $t }
+ forward_ref_binop! { impl const Rem, rem for $t, $t }
)*)
}
macro_rules! neg_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Neg for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Neg for $t {
type Output = $t;
#[inline]
fn neg(self) -> $t { -self }
}
- forward_ref_unop! { impl Neg, neg for $t }
+ forward_ref_unop! { impl const Neg, neg for $t }
)*)
}
macro_rules! add_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl AddAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const AddAssign for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn add_assign(&mut self, other: $t) { *self += other }
}
- forward_ref_op_assign! { impl AddAssign, add_assign for $t, $t }
+ forward_ref_op_assign! { impl const AddAssign, add_assign for $t, $t }
)+)
}
macro_rules! sub_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl SubAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const SubAssign for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn sub_assign(&mut self, other: $t) { *self -= other }
}
- forward_ref_op_assign! { impl SubAssign, sub_assign for $t, $t }
+ forward_ref_op_assign! { impl const SubAssign, sub_assign for $t, $t }
)+)
}
macro_rules! mul_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl MulAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const MulAssign for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn mul_assign(&mut self, other: $t) { *self *= other }
}
- forward_ref_op_assign! { impl MulAssign, mul_assign for $t, $t }
+ forward_ref_op_assign! { impl const MulAssign, mul_assign for $t, $t }
)+)
}
macro_rules! div_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl DivAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const DivAssign for $t {
#[inline]
fn div_assign(&mut self, other: $t) { *self /= other }
}
- forward_ref_op_assign! { impl DivAssign, div_assign for $t, $t }
+ forward_ref_op_assign! { impl const DivAssign, div_assign for $t, $t }
)+)
}
macro_rules! rem_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl RemAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const RemAssign for $t {
#[inline]
fn rem_assign(&mut self, other: $t) { *self %= other }
}
- forward_ref_op_assign! { impl RemAssign, rem_assign for $t, $t }
+ forward_ref_op_assign! { impl const RemAssign, rem_assign for $t, $t }
)+)
}
macro_rules! not_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl Not for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Not for $t {
type Output = $t;
#[inline]
fn not(self) -> $t { !self }
}
- forward_ref_unop! { impl Not, not for $t }
+ forward_ref_unop! { impl const Not, not for $t }
)*)
}
macro_rules! bitand_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitAnd for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitAnd for $t {
type Output = $t;
#[inline]
fn bitand(self, rhs: $t) -> $t { self & rhs }
}
- forward_ref_binop! { impl BitAnd, bitand for $t, $t }
+ forward_ref_binop! { impl const BitAnd, bitand for $t, $t }
)*)
}
macro_rules! bitor_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitOr for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOr for $t {
type Output = $t;
#[inline]
fn bitor(self, rhs: $t) -> $t { self | rhs }
}
- forward_ref_binop! { impl BitOr, bitor for $t, $t }
+ forward_ref_binop! { impl const BitOr, bitor for $t, $t }
)*)
}
macro_rules! bitxor_impl {
($($t:ty)*) => ($(
#[stable(feature = "rust1", since = "1.0.0")]
- impl BitXor for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitXor for $t {
type Output = $t;
#[inline]
fn bitxor(self, other: $t) -> $t { self ^ other }
}
- forward_ref_binop! { impl BitXor, bitxor for $t, $t }
+ forward_ref_binop! { impl const BitXor, bitxor for $t, $t }
)*)
}
macro_rules! shl_impl {
($t:ty, $f:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shl<$f> for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shl<$f> for $t {
type Output = $t;
#[inline]
}
}
- forward_ref_binop! { impl Shl, shl for $t, $f }
+ forward_ref_binop! { impl const Shl, shl for $t, $f }
};
}
macro_rules! shr_impl {
($t:ty, $f:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
- impl Shr<$f> for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const Shr<$f> for $t {
type Output = $t;
#[inline]
}
}
- forward_ref_binop! { impl Shr, shr for $t, $f }
+ forward_ref_binop! { impl const Shr, shr for $t, $f }
};
}
macro_rules! bitand_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitAndAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitAndAssign for $t {
#[inline]
fn bitand_assign(&mut self, other: $t) { *self &= other }
}
- forward_ref_op_assign! { impl BitAndAssign, bitand_assign for $t, $t }
+ forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for $t, $t }
)+)
}
macro_rules! bitor_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitOrAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitOrAssign for $t {
#[inline]
fn bitor_assign(&mut self, other: $t) { *self |= other }
}
- forward_ref_op_assign! { impl BitOrAssign, bitor_assign for $t, $t }
+ forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for $t, $t }
)+)
}
macro_rules! bitxor_assign_impl {
($($t:ty)+) => ($(
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl BitXorAssign for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const BitXorAssign for $t {
#[inline]
fn bitxor_assign(&mut self, other: $t) { *self ^= other }
}
- forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for $t, $t }
+ forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for $t, $t }
)+)
}
macro_rules! shl_assign_impl {
($t:ty, $f:ty) => {
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShlAssign<$f> for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShlAssign<$f> for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn shl_assign(&mut self, other: $f) {
}
}
- forward_ref_op_assign! { impl ShlAssign, shl_assign for $t, $f }
+ forward_ref_op_assign! { impl const ShlAssign, shl_assign for $t, $f }
};
}
macro_rules! shr_assign_impl {
($t:ty, $f:ty) => {
#[stable(feature = "op_assign_traits", since = "1.8.0")]
- impl ShrAssign<$f> for $t {
+ #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+ impl const ShrAssign<$f> for $t {
#[inline]
#[rustc_inherit_overflow_checks]
fn shr_assign(&mut self, other: $f) {
}
}
- forward_ref_op_assign! { impl ShrAssign, shr_assign for $t, $f }
+ forward_ref_op_assign! { impl const ShrAssign, shr_assign for $t, $f }
};
}
/// Having the enum makes it clearer -- no more wondering "wait, what did `false`
/// mean again?" -- and allows including a value.
///
+/// Similar to [`Option`] and [`Result`], this enum can be used with the `?` operator
+/// to return immediately if the [`Break`] variant is present or otherwise continue normally
+/// with the value inside the [`Continue`] variant.
+///
/// # Examples
///
/// Early-exiting from [`Iterator::try_for_each`]:
/// ```
///
/// A basic tree traversal:
-/// ```no_run
+/// ```
/// use std::ops::ControlFlow;
///
/// pub struct TreeNode<T> {
/// }
///
/// impl<T> TreeNode<T> {
-/// pub fn traverse_inorder<B>(&self, mut f: impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
+/// pub fn traverse_inorder<B>(&self, f: &mut impl FnMut(&T) -> ControlFlow<B>) -> ControlFlow<B> {
/// if let Some(left) = &self.left {
-/// left.traverse_inorder(&mut f)?;
+/// left.traverse_inorder(f)?;
/// }
/// f(&self.value)?;
/// if let Some(right) = &self.right {
-/// right.traverse_inorder(&mut f)?;
+/// right.traverse_inorder(f)?;
/// }
/// ControlFlow::Continue(())
/// }
+/// fn leaf(value: T) -> Option<Box<TreeNode<T>>> {
+/// Some(Box::new(Self { value, left: None, right: None }))
+/// }
/// }
+///
+/// let node = TreeNode {
+/// value: 0,
+/// left: TreeNode::leaf(1),
+/// right: Some(Box::new(TreeNode {
+/// value: -1,
+/// left: TreeNode::leaf(5),
+/// right: TreeNode::leaf(2),
+/// }))
+/// };
+/// let mut sum = 0;
+///
+/// let res = node.traverse_inorder(&mut |val| {
+/// if *val < 0 {
+/// ControlFlow::Break(*val)
+/// } else {
+/// sum += *val;
+/// ControlFlow::Continue(())
+/// }
+/// });
+/// assert_eq!(res, ControlFlow::Break(-1));
+/// assert_eq!(sum, 6);
/// ```
+///
+/// [`Break`]: ControlFlow::Break
+/// [`Continue`]: ControlFlow::Continue
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ControlFlow<B, C = ()> {
/// assert_eq!((1..12).start_bound(), Included(&1));
/// assert_eq!((1..12).start_bound().cloned(), Included(1));
/// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "bound_cloned", since = "1.55.0")]
pub fn cloned(self) -> Bound<T> {
match self {
/// # Examples
///
/// ```
- /// #![feature(option_result_unwrap_unchecked)]
/// let x = Some("air");
/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air");
/// ```
///
/// ```no_run
- /// #![feature(option_result_unwrap_unchecked)]
/// let x: Option<&str> = None;
/// assert_eq!(unsafe { x.unwrap_unchecked() }, "air"); // Undefined behavior!
/// ```
#[inline]
#[track_caller]
- #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
+ #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
pub unsafe fn unwrap_unchecked(self) -> T {
debug_assert!(self.is_some());
match self {
/// let copied = opt_x.copied();
/// assert_eq!(copied, Some(12));
/// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "copied", since = "1.35.0")]
#[rustc_const_unstable(feature = "const_option", issue = "67441")]
pub const fn copied(self) -> Option<T> {
/// assert_ne!(this_location.line(), another_location.line());
/// assert_ne!(this_location.column(), another_location.column());
/// ```
+ #[must_use]
#[stable(feature = "track_caller", since = "1.46.0")]
#[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
#[track_caller]
///
/// panic!("Normal panic");
/// ```
+ #[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn file(&self) -> &str {
self.file
///
/// panic!("Normal panic");
/// ```
+ #[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn line(&self) -> u32 {
self.line
///
/// panic!("Normal panic");
/// ```
+ #[must_use]
#[stable(feature = "panic_col", since = "1.25.0")]
pub fn column(&self) -> u32 {
self.col
///
/// panic!("Normal panic");
/// ```
+ #[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn payload(&self) -> &(dyn Any + Send) {
self.payload
/// If the `panic!` macro from the `core` crate (not from `std`)
/// was used with a formatting string and some additional arguments,
/// returns that message ready to be used for example with [`fmt::write`]
+ #[must_use]
#[unstable(feature = "panic_info_message", issue = "66745")]
pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
self.message
///
/// panic!("Normal panic");
/// ```
+ #[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn location(&self) -> Option<&Location<'_>> {
// NOTE: If this is changed to sometimes return None,
// never inline unless panic_immediate_abort to avoid code
// bloat at the call sites as much as possible
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
-pub fn panic(expr: &'static str) -> ! {
- if cfg!(feature = "panic_immediate_abort") {
- super::intrinsics::abort()
- }
-
+pub const fn panic(expr: &'static str) -> ! {
// Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
// reduce size overhead. The format_args! macro uses str's Display trait to
// write expr, which calls Formatter::pad, which must accommodate string
#[inline]
#[track_caller]
-#[lang = "panic_str"] // needed for const-evaluated panics
-pub fn panic_str(expr: &str) -> ! {
- panic_fmt(format_args!("{}", expr));
+#[lang = "panic_str"] // needed for `non-fmt-panics` lint
+pub const fn panic_str(expr: &str) -> ! {
+ panic_display(&expr);
}
#[inline]
#[track_caller]
-#[cfg_attr(not(bootstrap), lang = "panic_display")] // needed for const-evaluated panics
-pub fn panic_display<T: fmt::Display>(x: &T) -> ! {
+#[lang = "panic_display"] // needed for const-evaluated panics
+#[rustc_do_not_const_check] // hooked by const-eval
+pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
panic_fmt(format_args!("{}", *x));
}
#[cfg_attr(feature = "panic_immediate_abort", inline)]
#[track_caller]
#[lang = "panic_fmt"] // needed for const-evaluated panics
-pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
+#[rustc_do_not_const_check] // hooked by const-eval
+pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
super::intrinsics::abort()
}
///
/// ["pinning projections"]: self#projections-and-structural-pinning
#[inline(always)]
+ #[must_use]
#[rustc_const_unstable(feature = "const_pin", issue = "76654")]
#[stable(feature = "pin", since = "1.33.0")]
pub const fn get_ref(self) -> &'a T {
/// assert!(p.is_null());
/// ```
#[inline(always)]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
/// assert!(p.is_null());
/// ```
#[inline(always)]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
/// ```
#[stable(feature = "nonnull", since = "1.25.0")]
#[rustc_const_stable(feature = "const_nonnull_dangling", since = "1.36.0")]
+ #[must_use]
#[inline]
pub const fn dangling() -> Self {
// SAFETY: mem::align_of() returns a non-zero usize which is then casted
/// but `let slice = NonNull::from(&x[..]);` would be a better way to write code like this.)
#[unstable(feature = "nonnull_slice_from_raw_parts", issue = "71941")]
#[rustc_const_unstable(feature = "const_nonnull_slice_from_raw_parts", issue = "71941")]
+ #[must_use]
#[inline]
pub const fn slice_from_raw_parts(data: NonNull<T>, len: usize) -> Self {
// SAFETY: `data` is a `NonNull` pointer which is necessarily non-null
/// ```
#[unstable(feature = "slice_ptr_len", issue = "71146")]
#[rustc_const_unstable(feature = "const_slice_ptr_len", issue = "71146")]
+ #[must_use]
#[inline]
pub const fn len(self) -> usize {
self.as_ptr().len()
/// a `T`, which means this must not be used as a "not yet initialized"
/// sentinel value. Types that lazily allocate must track initialization by
/// some other means.
+ #[must_use]
#[inline]
pub const fn dangling() -> Self {
// SAFETY: mem::align_of() returns a valid, non-null pointer. The
/// # Examples
///
/// ```
- /// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Ok(2);
/// assert_eq!(unsafe { x.unwrap_unchecked() }, 2);
/// ```
///
/// ```no_run
- /// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Err("emergency failure");
/// unsafe { x.unwrap_unchecked(); } // Undefined behavior!
/// ```
#[inline]
#[track_caller]
- #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
+ #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
pub unsafe fn unwrap_unchecked(self) -> T {
debug_assert!(self.is_ok());
match self {
/// # Examples
///
/// ```no_run
- /// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Ok(2);
/// unsafe { x.unwrap_err_unchecked() }; // Undefined behavior!
/// ```
///
/// ```
- /// #![feature(option_result_unwrap_unchecked)]
/// let x: Result<u32, &str> = Err("emergency failure");
/// assert_eq!(unsafe { x.unwrap_err_unchecked() }, "emergency failure");
/// ```
#[inline]
#[track_caller]
- #[unstable(feature = "option_result_unwrap_unchecked", reason = "newly added", issue = "81383")]
+ #[stable(feature = "option_result_unwrap_unchecked", since = "1.58.0")]
pub unsafe fn unwrap_err_unchecked(self) -> E {
debug_assert!(self.is_err());
match self {
impl [u8] {
/// Checks if all bytes in this slice are within the ASCII range.
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[must_use]
#[inline]
pub fn is_ascii(&self) -> bool {
is_ascii(self)
/// 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")]
+ #[must_use]
#[inline]
pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
self.len() == other.len() && iter::zip(self, other).all(|(a, b)| a.eq_ignore_ascii_case(b))
/// 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.
+ #[must_use]
#[stable(feature = "chunks_exact", since = "1.31.0")]
pub fn remainder(&self) -> &'a [T] {
self.rem
/// 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.
+ #[must_use]
#[unstable(feature = "array_chunks", issue = "74985")]
pub fn remainder(&self) -> &'a [T] {
self.rem
/// 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.
+ #[must_use]
#[stable(feature = "rchunks", since = "1.31.0")]
pub fn remainder(&self) -> &'a [T] {
self.rem
}
/// Returns the first index matching the byte `x` in `text`.
+#[must_use]
#[inline]
pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
// Fast path for small slices
}
/// Returns the last index matching the byte `x` in `text`.
+#[must_use]
pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> {
// Scan for a single byte value by reading two `usize` words at a time.
//
/// # Examples
///
/// ```
- /// let mut v = ["a", "b", "c", "d"];
- /// v.swap(1, 3);
- /// assert!(v == ["a", "d", "c", "b"]);
+ /// let mut v = ["a", "b", "c", "d", "e"];
+ /// v.swap(2, 4);
+ /// assert!(v == ["a", "b", "e", "d", "c"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
/// [`copy_from_slice`]: slice::copy_from_slice
/// [`split_at_mut`]: slice::split_at_mut
#[stable(feature = "clone_from_slice", since = "1.7.0")]
+ #[track_caller]
pub fn clone_from_slice(&mut self, src: &[T])
where
T: Clone,
/// [`split_at_mut`]: slice::split_at_mut
#[doc(alias = "memcpy")]
#[stable(feature = "copy_from_slice", since = "1.9.0")]
+ #[track_caller]
pub fn copy_from_slice(&mut self, src: &[T])
where
T: Copy,
///
/// [`split_at_mut`]: slice::split_at_mut
#[stable(feature = "swap_with_slice", since = "1.27.0")]
+ #[track_caller]
pub fn swap_with_slice(&mut self, other: &mut [T]) {
assert!(self.len() == other.len(), "destination and source slices have different lengths");
// SAFETY: `self` is valid for `self.len()` elements by definition, and `src` was
where
T: Clone,
{
+ #[track_caller]
default fn spec_clone_from(&mut self, src: &[T]) {
assert!(self.len() == src.len(), "destination and source slices have different lengths");
// NOTE: We need to explicitly slice them to the same length
where
T: Copy,
{
+ #[track_caller]
fn spec_clone_from(&mut self, src: &[T]) {
self.copy_from_slice(src);
}
//! Free functions to create `&[T]` and `&mut [T]`.
use crate::array;
-use crate::intrinsics::is_aligned_and_not_null;
-use crate::mem;
use crate::ptr;
/// Forms a slice from a pointer and a length.
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[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"
- );
+#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
+ debug_check_data_len(data, len);
+
// SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
unsafe { &*ptr::slice_from_raw_parts(data, len) }
}
/// [`NonNull::dangling()`]: ptr::NonNull::dangling
#[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"
- );
+#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
+ debug_check_data_len(data as _, len);
+
// SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) }
}
+// In debug builds checks that `data` pointer is aligned and non-null and that slice with given `len` would cover less than half the address space
+#[cfg(all(not(bootstrap), debug_assertions))]
+#[unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+#[rustc_const_unstable(feature = "const_slice_from_raw_parts", issue = "67456")]
+const fn debug_check_data_len<T>(data: *const T, len: usize) {
+ fn rt_check<T>(data: *const T) {
+ use crate::intrinsics::is_aligned_and_not_null;
+
+ assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice");
+ }
+
+ const fn noop<T>(_: *const T) {}
+
+ // SAFETY:
+ //
+ // `rt_check` is just a debug assert to hint users that they are causing UB,
+ // it is not required for safety (the safety must be guatanteed by
+ // the `from_raw_parts[_mut]` caller).
+ //
+ // Since the checks are not required, we ignore them in CTFE as they can't
+ // be done there (alignment does not make much sense there).
+ unsafe {
+ crate::intrinsics::const_eval_select((data,), noop, rt_check);
+ }
+
+ assert!(
+ crate::mem::size_of::<T>().saturating_mul(len) <= isize::MAX as usize,
+ "attempt to create slice covering at least half the address space"
+ );
+}
+
+#[cfg(not(all(not(bootstrap), debug_assertions)))]
+const fn debug_check_data_len<T>(_data: *const T, _len: usize) {}
+
/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
/// assert_eq!(1, error.valid_up_to());
/// ```
#[stable(feature = "utf8_error", since = "1.5.0")]
+ #[must_use]
#[inline]
pub fn valid_up_to(&self) -> usize {
self.valid_up_to
///
/// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html
#[stable(feature = "utf8_error_error_len", since = "1.20.0")]
+ #[must_use]
#[inline]
pub fn error_len(&self) -> Option<usize> {
self.error_len.map(|len| len as usize)
/// [`char`]: prim@char
/// [`chars`]: str::chars
#[derive(Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Chars<'a> {
pub(super) iter: slice::Iter<'a, u8>,
/// [`char`]: prim@char
/// [`char_indices`]: str::char_indices
#[derive(Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct CharIndices<'a> {
pub(super) front_offset: usize,
/// assert_eq!(chars.next(), None);
/// ```
#[inline]
+ #[must_use]
#[unstable(feature = "char_indices_offset", issue = "83871")]
pub fn offset(&self) -> usize {
self.front_offset
/// See its documentation for more.
///
/// [`bytes`]: str::bytes
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone, Debug)]
pub struct Bytes<'a>(pub(super) Copied<slice::Iter<'a, u8>>);
///
/// [`lines`]: str::lines
#[stable(feature = "rust1", since = "1.0.0")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
pub struct Lines<'a>(pub(super) Map<SplitTerminator<'a, char>, LinesAnyMap>);
/// [`lines_any`]: str::lines_any
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[derive(Clone, Debug)]
#[allow(deprecated)]
pub struct LinesAny<'a>(pub(super) Lines<'a>);
}
/// Iterator over lossy UTF-8 string
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[unstable(feature = "str_internals", issue = "none")]
#[allow(missing_debug_implementations)]
pub struct Utf8LossyChunksIter<'a> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_str_len", since = "1.39.0")]
+ #[must_use]
#[inline]
pub const fn len(&self) -> usize {
self.as_bytes().len()
/// let s = "not empty";
/// assert!(!s.is_empty());
/// ```
- #[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_str_is_empty", since = "1.39.0")]
+ #[must_use]
+ #[inline]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")]
+ #[must_use]
#[inline]
pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str {
// SAFETY: the caller must uphold the safety contract for `get_unchecked`;
/// assert_eq!(" Martin-Löf", last);
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "str_split_at", since = "1.4.0")]
pub fn split_at(&self, mid: usize) -> (&str, &str) {
// is_char_boundary checks that the index is in [0, .len()]
/// assert_eq!("PER Martin-Löf", s);
/// ```
#[inline]
+ #[must_use]
#[stable(feature = "str_split_at", since = "1.4.0")]
pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) {
// is_char_boundary checks that the index is in [0, .len()]
/// If the pattern allows a reverse search but its results might differ
/// from a forward search, the [`rmatch_indices`] method can be used.
///
- /// [`rmatch_indices`]: str::match_indices
+ /// [`rmatch_indices`]: str::rmatch_indices
///
/// # Examples
///
/// assert!(!non_ascii.is_ascii());
/// ```
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[must_use]
#[inline]
pub fn is_ascii(&self) -> bool {
// We can treat each byte as character here: all multibyte characters
/// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS"));
/// ```
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
+ #[must_use]
#[inline]
pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
//! assert_eq!(s.find("you"), Some(4));
//! // char pattern
//! assert_eq!(s.find('n'), Some(2));
+//! // array of chars pattern
+//! assert_eq!(s.find(&['a', 'e', 'i', 'o', 'u']), Some(1));
//! // slice of chars pattern
//! assert_eq!(s.find(&['a', 'e', 'i', 'o', 'u'][..]), Some(1));
//! // closure pattern
/// assert_eq!("abaaa".find('b'), Some(1));
/// assert_eq!("abaaa".find('c'), None);
///
+/// // &[char; N]
+/// assert_eq!("ab".find(&['b', 'a']), Some(0));
+/// assert_eq!("abaaa".find(&['a', 'z']), Some(0));
+/// assert_eq!("abaaa".find(&['c', 'd']), None);
+///
/// // &[char]
/// assert_eq!("ab".find(&['b', 'a'][..]), Some(0));
/// assert_eq!("abaaa".find(&['a', 'z'][..]), Some(0));
}
}
+impl<const N: usize> MultiCharEq for [char; N] {
+ #[inline]
+ fn matches(&mut self, c: char) -> bool {
+ self.iter().any(|&m| m == c)
+ }
+}
+
+impl<const N: usize> MultiCharEq for &[char; N] {
+ #[inline]
+ fn matches(&mut self, c: char) -> bool {
+ self.iter().any(|&m| m == c)
+ }
+}
+
impl MultiCharEq for &[char] {
#[inline]
fn matches(&mut self, c: char) -> bool {
};
}
+/// Associated type for `<[char; N] as Pattern<'a>>::Searcher`.
+#[derive(Clone, Debug)]
+pub struct CharArraySearcher<'a, const N: usize>(
+ <MultiCharEqPattern<[char; N]> as Pattern<'a>>::Searcher,
+);
+
+/// Associated type for `<&[char; N] as Pattern<'a>>::Searcher`.
+#[derive(Clone, Debug)]
+pub struct CharArrayRefSearcher<'a, 'b, const N: usize>(
+ <MultiCharEqPattern<&'b [char; N]> as Pattern<'a>>::Searcher,
+);
+
+/// Searches for chars that are equal to any of the [`char`]s in the array.
+///
+/// # Examples
+///
+/// ```
+/// assert_eq!("Hello world".find(['l', 'l']), Some(2));
+/// assert_eq!("Hello world".find(['l', 'l']), Some(2));
+/// ```
+impl<'a, const N: usize> Pattern<'a> for [char; N] {
+ pattern_methods!(CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher);
+}
+
+unsafe impl<'a, const N: usize> Searcher<'a> for CharArraySearcher<'a, N> {
+ searcher_methods!(forward);
+}
+
+unsafe impl<'a, const N: usize> ReverseSearcher<'a> for CharArraySearcher<'a, N> {
+ searcher_methods!(reverse);
+}
+
+/// Searches for chars that are equal to any of the [`char`]s in the array.
+///
+/// # Examples
+///
+/// ```
+/// assert_eq!("Hello world".find(&['l', 'l']), Some(2));
+/// assert_eq!("Hello world".find(&['l', 'l']), Some(2));
+/// ```
+impl<'a, 'b, const N: usize> Pattern<'a> for &'b [char; N] {
+ pattern_methods!(CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher);
+}
+
+unsafe impl<'a, 'b, const N: usize> Searcher<'a> for CharArrayRefSearcher<'a, 'b, N> {
+ searcher_methods!(forward);
+}
+
+unsafe impl<'a, 'b, const N: usize> ReverseSearcher<'a> for CharArrayRefSearcher<'a, 'b, N> {
+ searcher_methods!(reverse);
+}
+
/////////////////////////////////////////////////////////////////////////////
// Impl for &[char]
/////////////////////////////////////////////////////////////////////////////
/// Implements substring slicing with syntax `&self[.. end]` or `&mut
/// self[.. end]`.
///
-/// Returns a slice of the given string from the byte range [`0`, `end`).
+/// Returns a slice of the given string from the byte range \[0, `end`).
/// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`.
///
/// This operation is *O*(1).
/// Implements substring slicing with syntax `&self[begin ..]` or `&mut
/// self[begin ..]`.
///
-/// Returns a slice of the given string from the byte range [`begin`,
-/// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin ..
-/// len]`.
+/// Returns a slice of the given string from the byte range \[`begin`, `len`).
+/// Equivalent to `&self[begin .. len]` or `&mut self[begin .. len]`.
///
/// This operation is *O*(1).
///
/// Implements substring slicing with syntax `&self[..= end]` or `&mut
/// self[..= end]`.
///
-/// Returns a slice of the given string from the byte range [0, `end`].
+/// Returns a slice of the given string from the byte range \[0, `end`\].
/// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum
/// value for `usize`.
///
// break if there is a nonascii byte
let zu = contains_nonascii(*block);
let zv = contains_nonascii(*block.offset(1));
- if zu | zv {
+ if zu || zv {
break;
}
}
/// Given a first byte, determines how many bytes are in this UTF-8 character.
#[unstable(feature = "str_internals", issue = "none")]
+#[must_use]
#[inline]
pub fn utf8_char_width(b: u8) -> usize {
UTF8_CHAR_WIDTH[b as usize] as usize
/// Returns a reference to the `Waker` for the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
+ #[must_use]
#[inline]
pub fn waker(&self) -> &'a Waker {
&self.waker
///
/// This function is primarily used for optimization purposes.
#[inline]
+ #[must_use]
#[stable(feature = "futures_api", since = "1.36.0")]
pub fn will_wake(&self, other: &Waker) -> bool {
self.waker == other.waker
/// ```
#[stable(feature = "duration_extras", since = "1.27.0")]
#[rustc_const_stable(feature = "duration_extras", since = "1.32.0")]
+ #[must_use]
#[inline]
pub const fn subsec_millis(&self) -> u32 {
self.nanos / NANOS_PER_MILLI
/// ```
#[stable(feature = "duration_extras", since = "1.27.0")]
#[rustc_const_stable(feature = "duration_extras", since = "1.32.0")]
+ #[must_use]
#[inline]
pub const fn subsec_micros(&self) -> u32 {
self.nanos / NANOS_PER_MICRO
/// ```
#[stable(feature = "duration", since = "1.3.0")]
#[rustc_const_stable(feature = "duration", since = "1.32.0")]
+ #[must_use]
#[inline]
pub const fn subsec_nanos(&self) -> u32 {
self.nanos
/// # Examples
/// ```
/// #![feature(duration_checked_float)]
- ///
/// use std::time::Duration;
///
/// let dur = Duration::try_from_secs_f64(2.7);
/// # Examples
/// ```
/// #![feature(duration_checked_float)]
- ///
/// use std::time::Duration;
///
/// let dur = Duration::try_from_secs_f32(2.7);
///
/// ```
/// #![feature(duration_checked_float)]
-///
/// use std::time::Duration;
///
/// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
#[test]
fn inference_works() {
let x = "a".to_string();
- x.eq_ignore_ascii_case("A");
+ let _ = x.eq_ignore_ascii_case("A");
}
// Shorthands used by the is_ascii_* tests.
#![feature(const_cell_into_inner)]
#![feature(const_convert)]
#![feature(const_maybe_uninit_assume_init)]
-#![cfg_attr(bootstrap, feature(const_panic))]
#![feature(const_ptr_read)]
#![feature(const_ptr_write)]
#![feature(const_ptr_offset)]
#![feature(const_raw_ptr_deref)]
#![feature(never_type)]
#![feature(unwrap_infallible)]
-#![feature(option_result_unwrap_unchecked)]
#![feature(result_into_ok_or_err)]
#![feature(ptr_metadata)]
#![feature(once_cell)]
if !n.is_finite() {
panic!("Invalid float literal {}", n);
}
- Literal(bridge::client::Literal::float(&n.to_string()))
+ let mut repr = n.to_string();
+ if !repr.contains('.') {
+ repr.push_str(".0");
+ }
+ Literal(bridge::client::Literal::float(&repr))
}
/// Creates a new suffixed floating-point literal.
if !n.is_finite() {
panic!("Invalid float literal {}", n);
}
- Literal(bridge::client::Literal::float(&n.to_string()))
+ let mut repr = n.to_string();
+ if !repr.contains('.') {
+ repr.push_str(".0");
+ }
+ Literal(bridge::client::Literal::float(&repr))
}
/// Creates a new suffixed floating-point literal.
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core" }
-libc = { version = "0.2.103", default-features = false, features = ['rustc-dep-of-std'] }
+libc = { version = "0.2.106", default-features = false, features = ['rustc-dep-of-std'] }
compiler_builtins = { version = "0.1.44" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
/// previous point in time. In some instances the `Backtrace` type may
/// internally be empty due to configuration. For more information see
/// `Backtrace::capture`.
+#[must_use]
pub struct Backtrace {
inner: Inner,
}
/// Returns the status of this backtrace, indicating whether this backtrace
/// request was unsupported, disabled, or a stack trace was actually
/// captured.
+ #[must_use]
pub fn status(&self) -> BacktraceStatus {
match self.inner {
Inner::Unsupported => BacktraceStatus::Unsupported,
impl<'a> Backtrace {
/// Returns an iterator over the backtrace frames.
+ #[must_use]
#[unstable(feature = "backtrace_frames", issue = "79676")]
pub fn frames(&'a self) -> &'a [BacktraceFrame] {
if let Inner::Captured(c) = &self.inner { &c.force().frames } else { &[] }
/// println!("key: {} val: {}", key, val);
/// }
/// ```
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter<'_, K, V> {
Iter { base: self.base.iter() }
/// println!("key: {} val: {}", key, val);
/// }
/// ```
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut { base: self.base.iter_mut() }
/// assert!(a.is_empty());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "drain", since = "1.6.0")]
pub fn drain(&mut self) -> Drain<'_, K, V> {
Drain { base: self.base.drain() }
/// assert_eq!(odds, vec![1, 3, 5, 7]);
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[unstable(feature = "hash_drain_filter", issue = "59618")]
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
where
/// assert_eq!(map.len(), 4);
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "retain_hash_collection", since = "1.18.0")]
pub fn retain<F>(&mut self, f: F)
where
/// assert_eq!(vec, ["a", "b", "c"]);
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub fn into_keys(self) -> IntoKeys<K, V> {
IntoKeys { inner: self.into_iter() }
/// assert_eq!(vec, [1, 2, 3]);
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "map_into_keys_values", since = "1.54.0")]
pub fn into_values(self) -> IntoValues<K, V> {
IntoValues { inner: self.into_iter() }
impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> {
/// Gets a reference to the key in the entry.
#[inline]
+ #[must_use]
#[unstable(feature = "hash_raw_entry", issue = "56167")]
pub fn key(&self) -> &K {
self.base.key()
/// Gets a mutable reference to the key in the entry.
#[inline]
+ #[must_use]
#[unstable(feature = "hash_raw_entry", issue = "56167")]
pub fn key_mut(&mut self) -> &mut K {
self.base.key_mut()
/// Gets a reference to the value in the entry.
#[inline]
+ #[must_use]
#[unstable(feature = "hash_raw_entry", issue = "56167")]
pub fn get(&self) -> &V {
self.base.get()
/// Gets a mutable reference to the value in the entry.
#[inline]
+ #[must_use]
#[unstable(feature = "hash_raw_entry", issue = "56167")]
pub fn get_mut(&mut self) -> &mut V {
self.base.get_mut()
/// Gets a reference to the key and value in the entry.
#[inline]
+ #[must_use]
#[unstable(feature = "hash_raw_entry", issue = "56167")]
pub fn get_key_value(&mut self) -> (&K, &V) {
self.base.get_key_value()
type IntoIter = Iter<'a, K, V>;
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
fn into_iter(self) -> Iter<'a, K, V> {
self.iter()
}
type IntoIter = IterMut<'a, K, V>;
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
fn into_iter(self) -> IterMut<'a, K, V> {
self.iter_mut()
}
/// let vec: Vec<(&str, i32)> = map.into_iter().collect();
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
fn into_iter(self) -> IntoIter<K, V> {
IntoIter { base: self.base.into_iter() }
}
/// }
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn iter(&self) -> Iter<'_, T> {
Iter { base: self.base.iter() }
/// assert!(set.is_empty());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "drain", since = "1.6.0")]
pub fn drain(&mut self) -> Drain<'_, T> {
Drain { base: self.base.drain() }
/// assert_eq!(odds, vec![1, 3, 5, 7]);
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[unstable(feature = "hash_drain_filter", issue = "59618")]
pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
where
/// assert_eq!(diff, [4].iter().collect());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn difference<'a>(&'a self, other: &'a HashSet<T, S>) -> Difference<'a, T, S> {
Difference { iter: self.iter(), other }
/// assert_eq!(diff1, [1, 4].iter().collect());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn symmetric_difference<'a>(
&'a self,
/// assert_eq!(intersection, [2, 3].iter().collect());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn intersection<'a>(&'a self, other: &'a HashSet<T, S>) -> Intersection<'a, T, S> {
if self.len() <= other.len() {
/// assert_eq!(union, [1, 2, 3, 4].iter().collect());
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn union<'a>(&'a self, other: &'a HashSet<T, S>) -> Union<'a, T, S> {
if self.len() >= other.len() {
/// set.retain(|&k| k % 2 == 0);
/// assert_eq!(set.len(), 3);
/// ```
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
#[stable(feature = "retain_hash_collection", since = "1.18.0")]
pub fn retain<F>(&mut self, f: F)
where
///
/// let mut intersection = a.intersection(&b);
/// ```
+#[must_use = "this returns the intersection as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Intersection<'a, T: 'a, S: 'a> {
// iterator of the first set
///
/// let mut difference = a.difference(&b);
/// ```
+#[must_use = "this returns the difference as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Difference<'a, T: 'a, S: 'a> {
// iterator of the first set
///
/// let mut intersection = a.symmetric_difference(&b);
/// ```
+#[must_use = "this returns the difference as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct SymmetricDifference<'a, T: 'a, S: 'a> {
iter: Chain<Difference<'a, T, S>, Difference<'a, T, S>>,
///
/// let mut union_iter = a.union(&b);
/// ```
+#[must_use = "this returns the union as an iterator, \
+ without modifying either input set"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Union<'a, T: 'a, S: 'a> {
iter: Chain<Iter<'a, T>, Difference<'a, T, S>>,
type IntoIter = Iter<'a, T>;
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
fn into_iter(self) -> Iter<'a, T> {
self.iter()
}
/// }
/// ```
#[inline]
- #[cfg_attr(not(bootstrap), rustc_lint_query_instability)]
fn into_iter(self) -> IntoIter<T> {
IntoIter { base: self.base.into_iter() }
}
/// ```
///
/// [`env::vars_os()`]: vars_os
+#[must_use]
#[stable(feature = "env", since = "1.0.0")]
pub fn vars() -> Vars {
Vars { inner: vars_os() }
/// println!("{:?}: {:?}", key, value);
/// }
/// ```
+#[must_use]
#[stable(feature = "env", since = "1.0.0")]
pub fn vars_os() -> VarsOs {
VarsOs { inner: os_imp::env() }
/// None => println!("{} is not defined in the environment.", key)
/// }
/// ```
+#[must_use]
#[stable(feature = "env", since = "1.0.0")]
pub fn var_os<K: AsRef<OsStr>>(key: K) -> Option<OsString> {
_var_os(key.as_ref())
/// documentation for more.
///
/// [`env::split_paths()`]: split_paths
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "env", since = "1.0.0")]
pub struct SplitPaths<'a> {
inner: os_imp::SplitPaths<'a>,
reason = "This function's behavior is unexpected and probably not what you want. \
Consider using a crate from crates.io instead."
)]
+#[must_use]
#[stable(feature = "env", since = "1.0.0")]
pub fn home_dir() -> Option<PathBuf> {
os_imp::home_dir()
/// println!("Temporary directory: {}", dir.display());
/// }
/// ```
+#[must_use]
#[stable(feature = "env", since = "1.0.0")]
pub fn temp_dir() -> PathBuf {
os_imp::temp_dir()
/// should not be relied upon for security purposes.
///
/// [`env::args()`]: args
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "env", since = "1.0.0")]
pub struct Args {
inner: ArgsOs,
/// should not be relied upon for security purposes.
///
/// [`env::args_os()`]: args_os
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "env", since = "1.0.0")]
pub struct ArgsOs {
inner: sys::args::Args,
pub fn atanh(self) -> f32 {
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
}
-
- /// Linear interpolation between `start` and `end`.
- ///
- /// This enables linear interpolation between `start` and `end`, where start is represented by
- /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all
- /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0
- /// at a given rate, the result will change from `start` to `end` at a similar rate.
- ///
- /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the
- /// range from `start` to `end`. This also is useful for transition functions which might
- /// move slightly past the end or start for a desired effect. Mathematically, the values
- /// returned are equivalent to `start + self * (end - start)`, although we make a few specific
- /// guarantees that are useful specifically to linear interpolation.
- ///
- /// These guarantees are:
- ///
- /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the
- /// value at 1.0 is always `end`. (exactness)
- /// * If `start` and `end` are [finite], the values will always move in the direction from
- /// `start` to `end` (monotonicity)
- /// * If `self` is [finite] and `start == end`, the value at any point will always be
- /// `start == end`. (consistency)
- ///
- /// [finite]: #method.is_finite
- #[must_use = "method returns a new number and does not mutate the original value"]
- #[unstable(feature = "float_interpolation", issue = "86269")]
- pub fn lerp(self, start: f32, end: f32) -> f32 {
- // consistent
- if start == end {
- start
-
- // exact/monotonic
- } else {
- self.mul_add(end, (-self).mul_add(start, start))
- }
- }
}
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
}
-
-#[test]
-fn test_lerp_exact() {
- // simple values
- assert_eq!(f32::lerp(0.0, 2.0, 4.0), 2.0);
- assert_eq!(f32::lerp(1.0, 2.0, 4.0), 4.0);
-
- // boundary values
- assert_eq!(f32::lerp(0.0, f32::MIN, f32::MAX), f32::MIN);
- assert_eq!(f32::lerp(1.0, f32::MIN, f32::MAX), f32::MAX);
-}
-
-#[test]
-fn test_lerp_consistent() {
- assert_eq!(f32::lerp(f32::MAX, f32::MIN, f32::MIN), f32::MIN);
- assert_eq!(f32::lerp(f32::MIN, f32::MAX, f32::MAX), f32::MAX);
-
- // as long as t is finite, a/b can be infinite
- assert_eq!(f32::lerp(f32::MAX, f32::NEG_INFINITY, f32::NEG_INFINITY), f32::NEG_INFINITY);
- assert_eq!(f32::lerp(f32::MIN, f32::INFINITY, f32::INFINITY), f32::INFINITY);
-}
-
-#[test]
-fn test_lerp_nan_infinite() {
- // non-finite t is not NaN if a/b different
- assert!(!f32::lerp(f32::INFINITY, f32::MIN, f32::MAX).is_nan());
- assert!(!f32::lerp(f32::NEG_INFINITY, f32::MIN, f32::MAX).is_nan());
-}
-
-#[test]
-fn test_lerp_values() {
- // just a few basic values
- assert_eq!(f32::lerp(0.25, 1.0, 2.0), 1.25);
- assert_eq!(f32::lerp(0.50, 1.0, 2.0), 1.50);
- assert_eq!(f32::lerp(0.75, 1.0, 2.0), 1.75);
-}
-
-#[test]
-fn test_lerp_monotonic() {
- // near 0
- let below_zero = f32::lerp(-f32::EPSILON, f32::MIN, f32::MAX);
- let zero = f32::lerp(0.0, f32::MIN, f32::MAX);
- let above_zero = f32::lerp(f32::EPSILON, f32::MIN, f32::MAX);
- assert!(below_zero <= zero);
- assert!(zero <= above_zero);
- assert!(below_zero <= above_zero);
-
- // near 0.5
- let below_half = f32::lerp(0.5 - f32::EPSILON, f32::MIN, f32::MAX);
- let half = f32::lerp(0.5, f32::MIN, f32::MAX);
- let above_half = f32::lerp(0.5 + f32::EPSILON, f32::MIN, f32::MAX);
- assert!(below_half <= half);
- assert!(half <= above_half);
- assert!(below_half <= above_half);
-
- // near 1
- let below_one = f32::lerp(1.0 - f32::EPSILON, f32::MIN, f32::MAX);
- let one = f32::lerp(1.0, f32::MIN, f32::MAX);
- let above_one = f32::lerp(1.0 + f32::EPSILON, f32::MIN, f32::MAX);
- assert!(below_one <= one);
- assert!(one <= above_one);
- assert!(below_one <= above_one);
-}
0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
}
- /// Linear interpolation between `start` and `end`.
- ///
- /// This enables linear interpolation between `start` and `end`, where start is represented by
- /// `self == 0.0` and `end` is represented by `self == 1.0`. This is the basis of all
- /// "transition", "easing", or "step" functions; if you change `self` from 0.0 to 1.0
- /// at a given rate, the result will change from `start` to `end` at a similar rate.
- ///
- /// Values below 0.0 or above 1.0 are allowed, allowing you to extrapolate values outside the
- /// range from `start` to `end`. This also is useful for transition functions which might
- /// move slightly past the end or start for a desired effect. Mathematically, the values
- /// returned are equivalent to `start + self * (end - start)`, although we make a few specific
- /// guarantees that are useful specifically to linear interpolation.
- ///
- /// These guarantees are:
- ///
- /// * If `start` and `end` are [finite], the value at 0.0 is always `start` and the
- /// value at 1.0 is always `end`. (exactness)
- /// * If `start` and `end` are [finite], the values will always move in the direction from
- /// `start` to `end` (monotonicity)
- /// * If `self` is [finite] and `start == end`, the value at any point will always be
- /// `start == end`. (consistency)
- ///
- /// [finite]: #method.is_finite
- #[must_use = "method returns a new number and does not mutate the original value"]
- #[unstable(feature = "float_interpolation", issue = "86269")]
- pub fn lerp(self, start: f64, end: f64) -> f64 {
- // consistent
- if start == end {
- start
-
- // exact/monotonic
- } else {
- self.mul_add(end, (-self).mul_add(start, start))
- }
- }
-
// Solaris/Illumos requires a wrapper around log, log2, and log10 functions
// because of their non-standard behavior (e.g., log(-n) returns -Inf instead
// of expected NaN).
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY));
assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan()));
}
-
-#[test]
-fn test_lerp_exact() {
- // simple values
- assert_eq!(f64::lerp(0.0, 2.0, 4.0), 2.0);
- assert_eq!(f64::lerp(1.0, 2.0, 4.0), 4.0);
-
- // boundary values
- assert_eq!(f64::lerp(0.0, f64::MIN, f64::MAX), f64::MIN);
- assert_eq!(f64::lerp(1.0, f64::MIN, f64::MAX), f64::MAX);
-}
-
-#[test]
-fn test_lerp_consistent() {
- assert_eq!(f64::lerp(f64::MAX, f64::MIN, f64::MIN), f64::MIN);
- assert_eq!(f64::lerp(f64::MIN, f64::MAX, f64::MAX), f64::MAX);
-
- // as long as t is finite, a/b can be infinite
- assert_eq!(f64::lerp(f64::MAX, f64::NEG_INFINITY, f64::NEG_INFINITY), f64::NEG_INFINITY);
- assert_eq!(f64::lerp(f64::MIN, f64::INFINITY, f64::INFINITY), f64::INFINITY);
-}
-
-#[test]
-fn test_lerp_nan_infinite() {
- // non-finite t is not NaN if a/b different
- assert!(!f64::lerp(f64::INFINITY, f64::MIN, f64::MAX).is_nan());
- assert!(!f64::lerp(f64::NEG_INFINITY, f64::MIN, f64::MAX).is_nan());
-}
-
-#[test]
-fn test_lerp_values() {
- // just a few basic values
- assert_eq!(f64::lerp(0.25, 1.0, 2.0), 1.25);
- assert_eq!(f64::lerp(0.50, 1.0, 2.0), 1.50);
- assert_eq!(f64::lerp(0.75, 1.0, 2.0), 1.75);
-}
-
-#[test]
-fn test_lerp_monotonic() {
- // near 0
- let below_zero = f64::lerp(-f64::EPSILON, f64::MIN, f64::MAX);
- let zero = f64::lerp(0.0, f64::MIN, f64::MAX);
- let above_zero = f64::lerp(f64::EPSILON, f64::MIN, f64::MAX);
- assert!(below_zero <= zero);
- assert!(zero <= above_zero);
- assert!(below_zero <= above_zero);
-
- // near 1
- let below_one = f64::lerp(1.0 - f64::EPSILON, f64::MIN, f64::MAX);
- let one = f64::lerp(1.0, f64::MIN, f64::MAX);
- let above_one = f64::lerp(1.0 + f64::EPSILON, f64::MIN, f64::MAX);
- assert!(below_one <= one);
- assert!(one <= above_one);
- assert!(below_one <= above_one);
-}
/// let nul_error = CString::new("foo bar\0").unwrap_err();
/// assert_eq!(nul_error.nul_position(), 7);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn nul_position(&self) -> usize {
self.0
}
/// Access the underlying UTF-8 error that was the cause of this error.
+ #[must_use]
#[stable(feature = "cstring_into", since = "1.7.0")]
pub fn utf8_error(&self) -> Utf8Error {
self.error
#[inline]
#[must_use]
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
- #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "none")]
+ #[rustc_const_unstable(feature = "const_cstr_unchecked", issue = "90343")]
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
// SAFETY: Casting to CStr is safe because its internal representation
// is a [u8] too (safe only inside std).
/// let boxed = c_string.into_boxed_c_str();
/// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed"));
/// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
#[stable(feature = "into_boxed_c_str", since = "1.20.0")]
pub fn into_c_string(self: Box<CStr>) -> CString {
let raw = Box::into_raw(self) as *mut [u8];
/// assert!(os_string.capacity() >= 10);
/// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ #[must_use]
#[inline]
pub fn capacity(&self) -> usize {
self.inner.capacity()
/// assert!(!os_str.is_empty());
/// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ #[must_use]
#[inline]
pub fn is_empty(&self) -> bool {
self.inner.inner.is_empty()
/// assert_eq!(os_str.len(), 3);
/// ```
#[stable(feature = "osstring_simple_functions", since = "1.9.0")]
+ #[must_use]
#[inline]
pub fn len(&self) -> usize {
self.inner.inner.len()
/// Converts a <code>[Box]<[OsStr]></code> into an [`OsString`] without copying or allocating.
#[stable(feature = "into_boxed_os_str", since = "1.20.0")]
+ #[must_use = "`self` will be dropped if the result is not used"]
pub fn into_os_string(self: Box<OsStr>) -> OsString {
let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
OsString { inner: Buf::from_box(boxed) }
/// assert!(!non_ascii.is_ascii());
/// ```
#[stable(feature = "osstring_ascii", since = "1.53.0")]
+ #[must_use]
#[inline]
pub fn is_ascii(&self) -> bool {
self.inner.is_ascii()
/// Ok(())
/// }
/// ```
+ #[must_use]
#[unstable(feature = "with_options", issue = "65439")]
pub fn with_options() -> OpenOptions {
OpenOptions::new()
/// Ok(())
/// }
/// ```
+ #[must_use]
#[stable(feature = "file_type", since = "1.1.0")]
pub fn file_type(&self) -> FileType {
FileType(self.0.file_type())
///
#[cfg_attr(unix, doc = "```no_run")]
#[cfg_attr(not(unix), doc = "```ignore")]
- /// #![feature(is_symlink)]
/// use std::fs;
/// use std::path::Path;
/// use std::os::unix::fs::symlink;
/// }
/// ```
#[must_use]
- #[unstable(feature = "is_symlink", issue = "85748")]
+ #[stable(feature = "is_symlink", since = "1.57.0")]
pub fn is_symlink(&self) -> bool {
self.file_type().is_symlink()
}
/// Ok(())
/// }
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn len(&self) -> u64 {
self.0.size()
/// Ok(())
/// }
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn permissions(&self) -> Permissions {
Permissions(self.0.perm())
/// Ok(())
/// }
/// ```
+ #[must_use = "call `set_readonly` to modify the readonly flag"]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn readonly(&self) -> bool {
self.0.readonly()
/// ```
///
/// The exact text, of course, depends on what files you have in `.`.
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn path(&self) -> PathBuf {
self.0.path()
/// }
/// }
/// ```
+ #[must_use]
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
pub fn file_name(&self) -> OsString {
self.0.file_name()
// "hard_link" should still appear as a symlink.
assert!(check!(fs::symlink_metadata(tmpdir.join("hard_link"))).file_type().is_symlink());
}
+
+/// Ensure `fs::create_dir` works on Windows with longer paths.
+#[test]
+#[cfg(windows)]
+fn create_dir_long_paths() {
+ use crate::{ffi::OsStr, iter, os::windows::ffi::OsStrExt};
+ const PATH_LEN: usize = 247;
+
+ let tmpdir = tmpdir();
+ let mut path = tmpdir.path().to_path_buf();
+ path.push("a");
+ let mut path = path.into_os_string();
+
+ let utf16_len = path.encode_wide().count();
+ if utf16_len >= PATH_LEN {
+ // Skip the test in the unlikely event the local user has a long temp directory path.
+ // This should not affect CI.
+ return;
+ }
+ // Increase the length of the path.
+ path.extend(iter::repeat(OsStr::new("a")).take(PATH_LEN - utf16_len));
+
+ // This should succeed.
+ fs::create_dir(&path).unwrap();
+
+ // This will fail if the path isn't converted to verbatim.
+ path.push("a");
+ fs::create_dir(&path).unwrap();
+}
/// println!("last OS error: {:?}", Error::last_os_error());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub fn last_os_error() -> Error {
Error::from_raw_os_error(sys::os::errno() as i32)
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub fn raw_os_error(&self) -> Option<i32> {
match self.repr {
/// }
/// ```
#[stable(feature = "io_error_inner", since = "1.3.0")]
+ #[must_use]
#[inline]
pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
match self.repr {
/// }
/// ```
#[stable(feature = "io_error_inner", since = "1.3.0")]
+ #[must_use]
#[inline]
pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
match self.repr {
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub fn kind(&self) -> ErrorKind {
match self.repr {
const DEFAULT_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
-pub(crate) fn cleanup() {
- stdio::cleanup()
-}
+pub(crate) use stdio::cleanup;
struct Guard<'a> {
buf: &'a mut Vec<u8>,
impl Initializer {
/// Returns a new `Initializer` which will zero out buffers.
#[unstable(feature = "read_initializer", issue = "42788")]
+ #[must_use]
#[inline]
pub fn zeroing() -> Initializer {
Initializer(true)
/// the method accurately reflects the number of bytes that have been
/// written to the head of the buffer.
#[unstable(feature = "read_initializer", issue = "42788")]
+ #[must_use]
#[inline]
pub unsafe fn nop() -> Initializer {
Initializer(false)
/// Indicates if a buffer should be initialized.
#[unstable(feature = "read_initializer", issue = "42788")]
+ #[must_use]
#[inline]
pub fn should_initialize(&self) -> bool {
self.0
/// Ok(())
/// }
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdin() -> Stdin {
static INSTANCE: SyncOnceCell<Mutex<BufReader<StdinRaw>>> = SyncOnceCell::new();
/// println!("got a chunk: {}", String::from_utf8_lossy(&split.unwrap()));
/// }
/// ```
+ #[must_use = "`self` will be dropped if the result is not used"]
#[unstable(feature = "stdin_forwarders", issue = "87096")]
pub fn split(self, byte: u8) -> Split<StdinLock<'static>> {
self.into_locked().split(byte)
/// Ok(())
/// }
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stdout() -> Stdout {
Stdout {
/// Ok(())
/// }
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stderr() -> Stderr {
// Note that unlike `stdout()` we don't use `at_exit` here to register a
/// io::empty().read_to_string(&mut buffer).unwrap();
/// assert!(buffer.is_empty());
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn empty() -> Empty {
/// io::repeat(0b101).read_exact(&mut buffer).unwrap();
/// assert_eq!(buffer, [0b101, 0b101, 0b101]);
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn repeat(byte: u8) -> Repeat {
/// let num_bytes = io::sink().write(&buffer).unwrap();
/// assert_eq!(num_bytes, 5);
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_io_structs", issue = "78812")]
pub const fn sink() -> Sink {
#![feature(const_cstr_unchecked)]
#![feature(const_fn_floating_point_arithmetic)]
#![feature(const_fn_fn_ptr_basics)]
+#![feature(const_fn_trait_bound)]
#![feature(const_format_args)]
#![feature(const_io_structs)]
#![feature(const_ip)]
#![feature(custom_test_frameworks)]
#![feature(decl_macro)]
#![feature(doc_cfg)]
-#![cfg_attr(not(bootstrap), feature(doc_cfg_hide))]
+#![feature(doc_cfg_hide)]
#![feature(doc_keyword)]
#![feature(doc_masked)]
#![feature(doc_notable_trait)]
#![feature(exact_size_is_empty)]
#![feature(exhaustive_patterns)]
#![feature(extend_one)]
-#![feature(float_interpolation)]
#![feature(fn_traits)]
#![feature(format_args_nl)]
#![feature(gen_future)]
#![feature(maybe_uninit_uninit_array)]
#![feature(min_specialization)]
#![feature(mixed_integer_ops)]
-#![cfg_attr(not(bootstrap), feature(must_not_suspend))]
+#![feature(must_not_suspend)]
#![feature(needs_panic_runtime)]
#![feature(negative_impls)]
#![feature(never_type)]
/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// assert_eq!(socket.ip(), IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
/// ```
+ #[must_use]
#[stable(feature = "ip_addr", since = "1.7.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn ip(&self) -> IpAddr {
/// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080);
/// assert_eq!(socket.port(), 8080);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn port(&self) -> u16 {
/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
/// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn ip(&self) -> &Ipv4Addr {
/// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
/// assert_eq!(socket.port(), 8080);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn port(&self) -> u16 {
/// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
/// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn ip(&self) -> &Ipv6Addr {
/// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
/// assert_eq!(socket.port(), 8080);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn port(&self) -> u16 {
/// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
/// assert_eq!(socket.flowinfo(), 10);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn flowinfo(&self) -> u32 {
/// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
/// assert_eq!(socket.scope_id(), 78);
/// ```
+ #[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_socketaddr", issue = "82485")]
pub const fn scope_id(&self) -> u32 {
/// ```
#[rustc_const_stable(feature = "const_ipv4", since = "1.50.0")]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub const fn octets(&self) -> [u8; 4] {
// This returns the order we want because s_addr is stored in big-endian.
#[must_use]
#[inline]
pub const fn is_documentation(&self) -> bool {
- match self.octets() {
- [192, 0, 2, _] => true,
- [198, 51, 100, _] => true,
- [203, 0, 113, _] => true,
- _ => false,
- }
+ matches!(self.octets(), [192, 0, 2, _] | [198, 51, 100, _] | [203, 0, 113, _])
}
/// Converts this address to an [IPv4-compatible] [`IPv6` address].
/// ```
#[rustc_const_stable(feature = "const_ipv6", since = "1.50.0")]
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub const fn segments(&self) -> [u16; 8] {
// All elements in `s6_addr` must be big endian.
/// ```
#[rustc_const_unstable(feature = "const_ipv6", issue = "76205")]
#[unstable(feature = "ip", issue = "27709")]
+ #[must_use]
#[inline]
pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
if self.is_multicast() {
/// ```
#[rustc_const_stable(feature = "const_ipv6", since = "1.32.0")]
#[stable(feature = "ipv6_to_octets", since = "1.12.0")]
+ #[must_use]
#[inline]
pub const fn octets(&self) -> [u8; 16] {
self.inner.s6_addr
/// See its documentation for more.
///
/// [`accept`]: TcpListener::accept
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Incoming<'a> {
#[unstable(feature = "c_size_t", issue = "88345")]
pub type c_size_t = usize;
-/// Equivalent to C's `ssize_t` type, from `stddef.h` (or `cstddef` for C++).
+/// Equivalent to C's `ptrdiff_t` type, from `stddef.h` (or `cstddef` for C++).
+///
+/// This type is currently always [`isize`], however in the future there may be
+/// platforms where this is not the case.
+#[unstable(feature = "c_size_t", issue = "88345")]
+pub type c_ptrdiff_t = isize;
+
+/// Equivalent to C's `ssize_t` (on POSIX) or `SSIZE_T` (on Windows) type.
///
/// This type is currently always [`isize`], however in the future there may be
/// platforms where this is not the case.
#[must_use]
#[stable(feature = "unix_socket", since = "1.10.0")]
pub fn is_unnamed(&self) -> bool {
- if let AddressKind::Unnamed = self.address() { true } else { false }
+ matches!(self.address(), AddressKind::Unnamed)
}
/// Returns the contents of this address if it is a `pathname` address.
}
/// Get the current PID.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_pid(&self) -> libc::pid_t {
self.0.pid
}
/// Get the current UID.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_uid(&self) -> libc::uid_t {
self.0.uid
}
/// Get the current GID.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn get_gid(&self) -> libc::gid_t {
self.0.gid
}
/// This struct is used to iterate through the control messages.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub struct Messages<'a> {
buffer: &'a [u8],
}
/// Returns the capacity of the buffer.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn capacity(&self) -> usize {
self.buffer.len()
}
/// Returns `true` if the ancillary data is empty.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn is_empty(&self) -> bool {
self.length == 0
}
/// Returns the number of used bytes.
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn len(&self) -> usize {
self.length
/// Ok(())
/// }
/// ```
+ #[must_use]
#[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
pub fn truncated(&self) -> bool {
self.truncated
/// }
/// ```
#[derive(Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "unix_socket", since = "1.10.0")]
pub struct Incoming<'a> {
listener: &'a UnixListener,
}
/// Returns the OS-assigned process identifier associated with this process's parent.
+#[must_use]
#[stable(feature = "unix_ppid", since = "1.27.0")]
pub fn parent_id() -> u32 {
crate::sys::os::getppid()
///
/// panic!("Normal panic");
/// ```
+#[must_use]
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
if thread::panicking() {
}
// Disregards ALWAYS_ABORT_FLAG
+ #[must_use]
pub fn get_count() -> usize {
LOCAL_PANIC_COUNT.with(|c| c.get())
}
// Disregards ALWAYS_ABORT_FLAG
+ #[must_use]
#[inline]
pub fn count_is_zero() -> bool {
if GLOBAL_PANIC_COUNT.load(Ordering::Relaxed) & !ALWAYS_ABORT_FLAG == 0 {
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
#[cold]
#[track_caller]
-pub fn begin_panic<M: Any + Send>(msg: M) -> ! {
+#[rustc_do_not_const_check] // hooked by const-eval
+pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
if cfg!(feature = "panic_immediate_abort") {
intrinsics::abort()
}
/// See [`Prefix`]'s documentation for more information on the different
/// kinds of prefixes.
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
#[inline]
pub fn kind(&self) -> Prefix<'a> {
self.parsed
///
/// [`components`]: Path::components
#[derive(Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Components<'a> {
// The path left to parse components from
///
/// [`iter`]: Path::iter
#[derive(Clone)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a> {
inner: Components<'a>,
///
/// [`ancestors`]: Path::ancestors
#[derive(Copy, Clone, Debug)]
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "path_ancestors", since = "1.28.0")]
pub struct Ancestors<'a> {
next: Option<&'a Path>,
///
/// [`capacity`]: OsString::capacity
#[stable(feature = "path_buf_capacity", since = "1.44.0")]
+ #[must_use]
#[inline]
pub fn capacity(&self) -> usize {
self.inner.capacity()
/// assert_eq!(grand_parent.parent(), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn parent(&self) -> Option<&Path> {
let mut comps = self.components();
let comp = comps.next_back();
/// assert_eq!(None, Path::new("/").file_name());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn file_name(&self) -> Option<&OsStr> {
self.components().next_back().and_then(|p| match p {
Component::Normal(p) => Some(p),
/// assert!(!Path::new("/etc/foo.rs").starts_with("/etc/foo"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
self._starts_with(base.as_ref())
}
/// assert!(!path.ends_with("conf")); // use .extension() instead
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
self._ends_with(child.as_ref())
}
/// [`Path::file_prefix`]: Path::file_prefix
///
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn file_stem(&self) -> Option<&OsStr> {
self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.or(after))
}
/// [`Path::file_stem`]: Path::file_stem
///
#[unstable(feature = "path_file_prefix", issue = "86319")]
+ #[must_use]
pub fn file_prefix(&self) -> Option<&OsStr> {
self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before))
}
/// assert_eq!("gz", Path::new("foo.tar.gz").extension().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn extension(&self) -> Option<&OsStr> {
self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.and(after))
}
/// assert_eq!(path.with_file_name("var"), PathBuf::from("/var"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
self._with_file_name(file_name.as_ref())
}
/// This is a convenience function that coerces errors to false. If you want to
/// check errors, call [`fs::metadata`].
#[stable(feature = "path_ext", since = "1.5.0")]
+ #[must_use]
#[inline]
pub fn exists(&self) -> bool {
fs::metadata(self).is_ok()
fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
}
- /// Returns true if the path exists on disk and is pointing at a symbolic link.
+ /// Returns `true` if the path exists on disk and is pointing at a symbolic link.
///
/// This function will not traverse symbolic links.
/// In case of a broken symbolic link this will also return true.
///
#[cfg_attr(unix, doc = "```no_run")]
#[cfg_attr(not(unix), doc = "```ignore")]
- /// #![feature(is_symlink)]
/// use std::path::Path;
/// use std::os::unix::fs::symlink;
///
/// assert_eq!(link_path.is_symlink(), true);
/// assert_eq!(link_path.exists(), false);
/// ```
- #[unstable(feature = "is_symlink", issue = "85748")]
+ ///
+ /// # See Also
+ ///
+ /// This is a convenience function that coerces errors to false. If you want to
+ /// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call
+ /// [`fs::Metadata::is_symlink`] if it was [`Ok`].
#[must_use]
+ #[stable(feature = "is_symlink", since = "1.57.0")]
pub fn is_symlink(&self) -> bool {
fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
}
/// Converts a [`Box<Path>`](Box) into a [`PathBuf`] without copying or
/// allocating.
#[stable(feature = "into_boxed_path", since = "1.20.0")]
+ #[must_use = "`self` will be dropped if the result is not used"]
pub fn into_path_buf(self: Box<Path>) -> PathBuf {
let rw = Box::into_raw(self) as *mut OsStr;
let inner = unsafe { Box::from_raw(rw) };
/// let cmd = Command::new("echo");
/// assert_eq!(cmd.get_program(), "echo");
/// ```
+ #[must_use]
#[stable(feature = "command_access", since = "1.57.0")]
pub fn get_program(&self) -> &OsStr {
self.inner.get_program()
/// cmd.current_dir("/bin");
/// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin")));
/// ```
+ #[must_use]
#[stable(feature = "command_access", since = "1.57.0")]
pub fn get_current_dir(&self) -> Option<&Path> {
self.inner.get_current_dir()
///
/// This struct is created by [`Command::get_args`]. See its documentation for
/// more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "command_access", since = "1.57.0")]
#[derive(Debug)]
pub struct CommandArgs<'a> {
/// its entire stdin before writing more than a pipe buffer's worth of output.
/// The size of a pipe buffer varies on different targets.
///
+ #[must_use]
#[stable(feature = "process", since = "1.0.0")]
pub fn piped() -> Stdio {
Stdio(imp::Stdio::MakePipe)
/// print!("You piped in the reverse of: ");
/// io::stdout().write_all(&output.stdout).unwrap();
/// ```
+ #[must_use]
#[stable(feature = "process", since = "1.0.0")]
pub fn inherit() -> Stdio {
Stdio(imp::Stdio::Inherit)
/// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
/// // Ignores any piped-in input
/// ```
+ #[must_use]
#[stable(feature = "process", since = "1.0.0")]
pub fn null() -> Stdio {
Stdio(imp::Stdio::Null)
/// println!("failed to create 'projects/' directory: {}", status);
/// }
/// ```
+ #[must_use]
#[stable(feature = "process", since = "1.0.0")]
pub fn success(&self) -> bool {
self.0.exit_ok().is_ok()
/// None => println!("Process terminated by signal")
/// }
/// ```
+ #[must_use]
#[stable(feature = "process", since = "1.0.0")]
pub fn code(&self) -> Option<i32> {
self.0.code()
/// assert_eq!(bad.code(), Some(1));
/// # } // #[cfg(unix)]
/// ```
+ #[must_use]
pub fn code(&self) -> Option<i32> {
self.code_nonzero().map(Into::into)
}
/// assert_eq!(bad.code_nonzero().unwrap(), NonZeroI32::try_from(1).unwrap());
/// # } // cfg!(unix)
/// ```
+ #[must_use]
pub fn code_nonzero(&self) -> Option<NonZeroI32> {
self.0.code()
}
/// Converts an `ExitStatusError` (back) to an `ExitStatus`.
+ #[must_use]
pub fn into_status(&self) -> ExitStatus {
ExitStatus(self.0.into())
}
/// println!("ls command didn't start");
/// }
/// ```
+ #[must_use]
#[stable(feature = "process_id", since = "1.3.0")]
pub fn id(&self) -> u32 {
self.handle.id()
/// ```
///
///
+#[must_use]
#[stable(feature = "getpid", since = "1.26.0")]
pub fn id() -> u32 {
crate::sys::os::getpid()
let ret_code = panic::catch_unwind(move || panic::catch_unwind(main).unwrap_or(101) as isize)
.map_err(move |e| {
mem::forget(e);
- rtprintpanic!("drop of the panic payload panicked");
- sys::abort_internal()
+ rtabort!("drop of the panic payload panicked");
});
panic::catch_unwind(cleanup).map_err(rt_abort)?;
ret_code
/// }
/// }
/// ```
+ #[must_use]
#[stable(feature = "wait_timeout", since = "1.5.0")]
pub fn timed_out(&self) -> bool {
self.0
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(align(64))]
-pub(super) struct Aligner;
-
-#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub(super) struct CacheAligned<T>(pub T, pub Aligner);
+pub(super) struct CacheAligned<T>(pub T);
impl<T> Deref for CacheAligned<T> {
type Target = T;
impl<T> CacheAligned<T> {
pub(super) fn new(t: T) -> Self {
- CacheAligned(t, Aligner)
+ CacheAligned(t)
}
}
/// // Let's see what that answer was
/// println!("{:?}", receiver.recv().unwrap());
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
let a = Arc::new(oneshot::Packet::new());
/// assert_eq!(receiver.recv().unwrap(), 1);
/// assert_eq!(receiver.recv().unwrap(), 2);
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn sync_channel<T>(bound: usize) -> (SyncSender<T>, Receiver<T>) {
let a = Arc::new(sync::Packet::new(bound));
mutex.lock();
}
- pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
- panic!("wait_timeout not supported on hermit");
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ self.counter.fetch_add(1, SeqCst);
+ mutex.unlock();
+ let millis = dur.as_millis().min(u32::MAX as u128) as u32;
+
+ let res = if millis > 0 {
+ abi::sem_timedwait(self.sem1, millis)
+ } else {
+ abi::sem_trywait(self.sem1)
+ };
+
+ abi::sem_post(self.sem2);
+ mutex.lock();
+ res == 0
}
pub unsafe fn destroy(&self) {
unsafe { crate::hint::unreachable_unchecked() };
}
-pub fn available_concurrency() -> io::Result<crate::num::NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<crate::num::NonZeroUsize> {
super::unsupported()
}
pub use self::imp::init;
pub struct Handler {
- _data: *mut libc::c_void,
+ data: *mut libc::c_void,
}
impl Handler {
}
fn null() -> Handler {
- Handler { _data: crate::ptr::null_mut() }
+ Handler { data: crate::ptr::null_mut() }
}
}
impl Drop for Handler {
fn drop(&mut self) {
unsafe {
- drop_handler(self);
+ drop_handler(self.data);
}
}
}
}
let handler = make_handler();
- MAIN_ALTSTACK.store(handler._data, Ordering::Relaxed);
+ MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed);
mem::forget(handler);
}
pub unsafe fn cleanup() {
- Handler { _data: MAIN_ALTSTACK.load(Ordering::Relaxed) };
+ drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed));
}
unsafe fn get_stackp() -> *mut libc::c_void {
if stack.ss_flags & SS_DISABLE != 0 {
stack = get_stack();
sigaltstack(&stack, ptr::null_mut());
- Handler { _data: stack.ss_sp as *mut libc::c_void }
+ Handler { data: stack.ss_sp as *mut libc::c_void }
} else {
Handler::null()
}
}
- pub unsafe fn drop_handler(handler: &mut Handler) {
- if !handler._data.is_null() {
+ pub unsafe fn drop_handler(data: *mut libc::c_void) {
+ if !data.is_null() {
let stack = libc::stack_t {
ss_sp: ptr::null_mut(),
ss_flags: SS_DISABLE,
sigaltstack(&stack, ptr::null_mut());
// We know from `get_stackp` that the alternate stack we installed is part of a mapping
// that started one page earlier, so walk back a page and unmap from there.
- munmap(handler._data.sub(page_size()), SIGSTKSZ + page_size());
+ munmap(data.sub(page_size()), SIGSTKSZ + page_size());
}
}
}
super::Handler::null()
}
- pub unsafe fn drop_handler(_handler: &mut super::Handler) {}
+ pub unsafe fn drop_handler(_data: *mut libc::c_void) {}
}
target_os = "solaris",
target_os = "illumos",
))] {
+ #[cfg(any(target_os = "android", target_os = "linux"))]
+ {
+ let mut set: libc::cpu_set_t = unsafe { mem::zeroed() };
+ if unsafe { libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) } == 0 {
+ let count = unsafe { libc::CPU_COUNT(&set) };
+ return Ok(unsafe { NonZeroUsize::new_unchecked(count as usize) });
+ }
+ }
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
-1 => Err(io::Error::last_os_error()),
0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")),
cchCount2: c_int,
bIgnoreCase: BOOL,
) -> c_int;
+ pub fn GetFullPathNameW(
+ lpFileName: LPCWSTR,
+ nBufferLength: DWORD,
+ lpBuffer: LPWSTR,
+ lpFilePart: *mut LPWSTR,
+ ) -> DWORD;
}
#[link(name = "ws2_32")]
use crate::sys::{c, cvt};
use crate::sys_common::{AsInner, FromInner, IntoInner};
+use super::path::maybe_verbatim;
use super::to_u16s;
pub struct File {
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
- let path = to_u16s(path)?;
+ let path = maybe_verbatim(path)?;
let handle = unsafe {
c::CreateFileW(
path.as_ptr(),
}
pub fn mkdir(&self, p: &Path) -> io::Result<()> {
- let p = to_u16s(p)?;
+ let p = maybe_verbatim(p)?;
cvt(unsafe { c::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) })?;
Ok(())
}
pub fn readdir(p: &Path) -> io::Result<ReadDir> {
let root = p.to_path_buf();
let star = p.join("*");
- let path = to_u16s(&star)?;
+ let path = maybe_verbatim(&star)?;
unsafe {
let mut wfd = mem::zeroed();
}
pub fn unlink(p: &Path) -> io::Result<()> {
- let p_u16s = to_u16s(p)?;
+ let p_u16s = maybe_verbatim(p)?;
cvt(unsafe { c::DeleteFileW(p_u16s.as_ptr()) })?;
Ok(())
}
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
- let old = to_u16s(old)?;
- let new = to_u16s(new)?;
+ let old = maybe_verbatim(old)?;
+ let new = maybe_verbatim(new)?;
cvt(unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) })?;
Ok(())
}
pub fn rmdir(p: &Path) -> io::Result<()> {
- let p = to_u16s(p)?;
+ let p = maybe_verbatim(p)?;
cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?;
Ok(())
}
pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()> {
let original = to_u16s(original)?;
- let link = to_u16s(link)?;
+ let link = maybe_verbatim(link)?;
let flags = if dir { c::SYMBOLIC_LINK_FLAG_DIRECTORY } else { 0 };
// Formerly, symlink creation required the SeCreateSymbolicLink privilege. For the Windows 10
// Creators Update, Microsoft loosened this to allow unprivileged symlink creation if the
#[cfg(not(target_vendor = "uwp"))]
pub fn link(original: &Path, link: &Path) -> io::Result<()> {
- let original = to_u16s(original)?;
- let link = to_u16s(link)?;
+ let original = maybe_verbatim(original)?;
+ let link = maybe_verbatim(link)?;
cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?;
Ok(())
}
}
pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
- let p = to_u16s(p)?;
+ let p = maybe_verbatim(p)?;
unsafe {
cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?;
Ok(())
}
c::PROGRESS_CONTINUE
}
- let pfrom = to_u16s(from)?;
- let pto = to_u16s(to)?;
+ let pfrom = maybe_verbatim(from)?;
+ let pto = maybe_verbatim(to)?;
let mut size = 0i64;
cvt(unsafe {
c::CopyFileExW(
+use super::{c, fill_utf16_buf, to_u16s};
use crate::ffi::OsStr;
+use crate::io;
use crate::mem;
+use crate::path::Path;
use crate::path::Prefix;
+use crate::ptr;
#[cfg(test)]
mod tests;
None => (path, OsStr::new("")),
}
}
+
+/// Returns a UTF-16 encoded path capable of bypassing the legacy `MAX_PATH` limits.
+///
+/// This path may or may not have a verbatim prefix.
+pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
+ // Normally the MAX_PATH is 260 UTF-16 code units (including the NULL).
+ // However, for APIs such as CreateDirectory[1], the limit is 248.
+ //
+ // [1]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createdirectorya#parameters
+ const LEGACY_MAX_PATH: usize = 248;
+ // UTF-16 encoded code points, used in parsing and building UTF-16 paths.
+ // All of these are in the ASCII range so they can be cast directly to `u16`.
+ const SEP: u16 = b'\\' as _;
+ const ALT_SEP: u16 = b'/' as _;
+ const QUERY: u16 = b'?' as _;
+ const COLON: u16 = b':' as _;
+ const DOT: u16 = b'.' as _;
+ const U: u16 = b'U' as _;
+ const N: u16 = b'N' as _;
+ const C: u16 = b'C' as _;
+
+ // \\?\
+ const VERBATIM_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP];
+ // \??\
+ const NT_PREFIX: &[u16] = &[SEP, QUERY, QUERY, SEP];
+ // \\?\UNC\
+ const UNC_PREFIX: &[u16] = &[SEP, SEP, QUERY, SEP, U, N, C, SEP];
+
+ let mut path = to_u16s(path)?;
+ if path.starts_with(VERBATIM_PREFIX) || path.starts_with(NT_PREFIX) {
+ // Early return for paths that are already verbatim.
+ return Ok(path);
+ } else if path.len() < LEGACY_MAX_PATH {
+ // Early return if an absolute path is less < 260 UTF-16 code units.
+ // This is an optimization to avoid calling `GetFullPathNameW` unnecessarily.
+ match path.as_slice() {
+ // Starts with `D:`, `D:\`, `D:/`, etc.
+ // Does not match if the path starts with a `\` or `/`.
+ [drive, COLON, 0] | [drive, COLON, SEP | ALT_SEP, ..]
+ if *drive != SEP && *drive != ALT_SEP =>
+ {
+ return Ok(path);
+ }
+ // Starts with `\\`, `//`, etc
+ [SEP | ALT_SEP, SEP | ALT_SEP, ..] => return Ok(path),
+ _ => {}
+ }
+ }
+
+ // Firstly, get the absolute path using `GetFullPathNameW`.
+ // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
+ let lpfilename = path.as_ptr();
+ fill_utf16_buf(
+ // SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid.
+ // `lpfilename` is a pointer to a null terminated string that is not
+ // invalidated until after `GetFullPathNameW` returns successfully.
+ |buffer, size| unsafe {
+ // While the docs for `GetFullPathNameW` have the standard note
+ // about needing a `\\?\` path for a long lpfilename, this does not
+ // appear to be true in practice.
+ // See:
+ // https://stackoverflow.com/questions/38036943/getfullpathnamew-and-long-windows-file-paths
+ // https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
+ c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut())
+ },
+ |mut absolute| {
+ path.clear();
+
+ // Secondly, add the verbatim prefix. This is easier here because we know the
+ // path is now absolute and fully normalized (e.g. `/` has been changed to `\`).
+ let prefix = match absolute {
+ // C:\ => \\?\C:\
+ [_, COLON, SEP, ..] => VERBATIM_PREFIX,
+ // \\.\ => \\?\
+ [SEP, SEP, DOT, SEP, ..] => {
+ absolute = &absolute[4..];
+ VERBATIM_PREFIX
+ }
+ // Leave \\?\ and \??\ as-is.
+ [SEP, SEP, QUERY, SEP, ..] | [SEP, QUERY, QUERY, SEP, ..] => &[],
+ // \\ => \\?\UNC\
+ [SEP, SEP, ..] => {
+ absolute = &absolute[2..];
+ UNC_PREFIX
+ }
+ // Anything else we leave alone.
+ _ => &[],
+ };
+
+ path.reserve_exact(prefix.len() + absolute.len() + 1);
+ path.extend_from_slice(prefix);
+ path.extend_from_slice(absolute);
+ path.push(0);
+ },
+ )?;
+ Ok(path)
+}
(OsStr::new(r"server"), OsStr::new(r"\\\\\\\\\\\\\share"))
);
}
+
+#[test]
+fn verbatim() {
+ use crate::path::Path;
+ fn check(path: &str, expected: &str) {
+ let verbatim = maybe_verbatim(Path::new(path)).unwrap();
+ let verbatim = String::from_utf16_lossy(verbatim.strip_suffix(&[0]).unwrap());
+ assert_eq!(&verbatim, expected, "{}", path);
+ }
+
+ // Ensure long paths are correctly prefixed.
+ check(
+ r"C:\Program Files\Rust\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ r"\\?\C:\Program Files\Rust\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ );
+ check(
+ r"\\server\share\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ r"\\?\UNC\server\share\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ );
+ check(
+ r"\\.\PIPE\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ r"\\?\PIPE\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ );
+ // `\\?\` prefixed paths are left unchanged...
+ check(
+ r"\\?\verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ r"\\?\verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ );
+ // But `//?/` is not a verbatim prefix so it will be normalized.
+ check(
+ r"//?/E:/verbatim.\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ r"\\?\E:\verbatim\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\foo.txt",
+ );
+
+ // For performance, short absolute paths are left unchanged.
+ check(r"C:\Program Files\Rust", r"C:\Program Files\Rust");
+ check(r"\\server\share", r"\\server\share");
+ check(r"\\.\COM1", r"\\.\COM1");
+
+ // Check that paths of length 247 are converted to verbatim.
+ // This is necessary for `CreateDirectory`.
+ check(
+ r"C:\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ r"\\?\C:\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ );
+
+ // Make sure opening a drive will work.
+ check("Z:", "Z:");
+
+ // An empty path or a path that contains null are not valid paths.
+ assert!(maybe_verbatim(Path::new("")).is_err());
+ assert!(maybe_verbatim(Path::new("\0")).is_err());
+}
+//! Implements thread-local destructors that are not associated with any
+//! particular data.
+
#![unstable(feature = "thread_local_internals", issue = "none")]
#![cfg(target_thread_local)]
-pub use crate::sys_common::thread_local_dtor::register_dtor_fallback as register_dtor;
+// Using a per-thread list avoids the problems in synchronizing global state.
+#[thread_local]
+static mut DESTRUCTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
+
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+ DESTRUCTORS.push((t, dtor));
+}
+
+/// Runs destructors. This should not be called until thread exit.
+pub unsafe fn run_keyless_dtors() {
+ // Drop all the destructors.
+ //
+ // Note: While this is potentially an infinite loop, it *should* be
+ // the case that this loop always terminates because we provide the
+ // guarantee that a TLS key cannot be set after it is flagged for
+ // destruction.
+ while let Some((ptr, dtor)) = DESTRUCTORS.pop() {
+ (dtor)(ptr);
+ }
+ // We're done so free the memory.
+ DESTRUCTORS = Vec::new();
+}
unsafe extern "system" fn on_tls_callback(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID) {
if dwReason == c::DLL_THREAD_DETACH || dwReason == c::DLL_PROCESS_DETACH {
run_dtors();
+ #[cfg(target_thread_local)]
+ super::thread_local_dtor::run_keyless_dtors();
}
// See comments above for what this is doing. Note that we don't need this
/// This struct is created by
/// [`Command::get_envs`][crate::process::Command::get_envs]. See its
/// documentation for more.
+#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "command_access", since = "1.57.0")]
#[derive(Debug)]
pub struct CommandEnvs<'a> {
}
}
-/// Returns a slice of the given string for the byte range [`begin`..`end`).
+/// Returns a slice of the given string for the byte range \[`begin`..`end`).
///
/// # Panics
///
/// [`unwrap`]: crate::result::Result::unwrap
/// [naming-threads]: ./index.html#naming-threads
/// [stack-size]: ./index.html#stack-size
+#[must_use = "must eventually spawn the thread"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Builder {
///
/// handler.join().unwrap();
/// ```
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn current() -> Thread {
thread_info::current_thread().expect(
///
/// [Mutex]: crate::sync::Mutex
#[inline]
+#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn panicking() -> bool {
panicking::panicking()
/// assert!(thread::current().id() != other_thread_id);
/// ```
#[stable(feature = "thread_id", since = "1.19.0")]
+ #[must_use]
pub fn id(&self) -> ThreadId {
self.inner.id
}
///
/// [naming-threads]: ./index.html#naming-threads
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn name(&self) -> Option<&str> {
self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
}
/// println!("thread id: {:?}", thread.id());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
pub fn thread(&self) -> &Thread {
&self.0.thread
}
pub fn join(mut self) -> Result<T> {
self.0.join()
}
+
+ /// Checks if the the associated thread is still running its main function.
+ ///
+ /// This might return `false` for a brief moment after the thread's main
+ /// function has returned, but before the thread itself has stopped running.
+ #[unstable(feature = "thread_is_running", issue = "90470")]
+ pub fn is_running(&self) -> bool {
+ Arc::strong_count(&self.0.packet.0) > 1
+ }
}
impl<T> AsInner<imp::Thread> for JoinHandle<T> {
use crate::any::Any;
use crate::mem;
use crate::result;
-use crate::sync::mpsc::{channel, Sender};
+use crate::sync::{
+ mpsc::{channel, Sender},
+ Arc, Barrier,
+};
use crate::thread::{self, ThreadId};
use crate::time::Duration;
+use crate::time::Instant;
// !!! These tests are dangerous. If something is buggy, they will hang, !!!
// !!! instead of exiting cleanly. This might wedge the buildbots. !!!
rx.recv().unwrap();
}
+#[test]
+fn test_is_running() {
+ let b = Arc::new(Barrier::new(2));
+ let t = thread::spawn({
+ let b = b.clone();
+ move || {
+ b.wait();
+ 1234
+ }
+ });
+
+ // Thread is definitely running here, since it's still waiting for the barrier.
+ assert_eq!(t.is_running(), true);
+
+ // Unblock the barrier.
+ b.wait();
+
+ // Now check that t.is_running() becomes false within a reasonable time.
+ let start = Instant::now();
+ while t.is_running() {
+ assert!(start.elapsed() < Duration::from_secs(2));
+ thread::sleep(Duration::from_millis(15));
+ }
+
+ // Joining the thread should not block for a significant time now.
+ let join_time = Instant::now();
+ assert_eq!(t.join().unwrap(), 1234);
+ assert!(join_time.elapsed() < Duration::from_secs(2));
+}
+
#[test]
fn test_join_panic() {
match thread::spawn(move || panic!()).join() {
///
/// let now = Instant::now();
/// ```
+ #[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn now() -> Instant {
let os_now = time::Instant::now();
/// let new_now = Instant::now();
/// println!("{:?}", new_now.duration_since(now));
/// ```
+ #[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn duration_since(&self, earlier: Instant) -> Duration {
self.0.checked_sub_instant(&earlier.0).expect("supplied instant is later than self")
/// println!("{:?}", new_now.checked_duration_since(now));
/// println!("{:?}", now.checked_duration_since(new_now)); // None
/// ```
+ #[must_use]
#[stable(feature = "checked_duration_since", since = "1.39.0")]
pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
self.0.checked_sub_instant(&earlier.0)
/// println!("{:?}", new_now.saturating_duration_since(now));
/// println!("{:?}", now.saturating_duration_since(new_now)); // 0ns
/// ```
+ #[must_use]
#[stable(feature = "checked_duration_since", since = "1.39.0")]
pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
self.checked_duration_since(earlier).unwrap_or_default()
/// sleep(three_secs);
/// assert!(instant.elapsed() >= three_secs);
/// ```
+ #[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn elapsed(&self) -> Duration {
Instant::now() - *self
///
/// let sys_time = SystemTime::now();
/// ```
+ #[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn now() -> SystemTime {
SystemTime(time::SystemTime::now())
/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()),
/// }
/// ```
+ #[must_use]
#[stable(feature = "time2", since = "1.8.0")]
pub fn duration(&self) -> Duration {
self.0
#[test]
fn instant_elapsed() {
let a = Instant::now();
- a.elapsed();
+ let _ = a.elapsed();
}
#[test]
#[should_panic]
fn instant_duration_since_panic() {
let a = Instant::now();
- (a - Duration::SECOND).duration_since(a);
+ let _ = (a - Duration::SECOND).duration_since(a);
}
#[test]
_stdout: &[u8],
_state: &ConsoleTestState,
) -> io::Result<()> {
- // Because the testsuit node holds some of the information as attributes, we can't write it
- // until all of the tests has ran. Instead of writting every result as they come in, we add
+ // Because the testsuite node holds some of the information as attributes, we can't write it
+ // until all of the tests have finished. Instead of writing every result as they come in, we add
// them to a Vec and write them all at once when run is complete.
let duration = exec_time.map(|t| t.0).unwrap_or_default();
self.results.push((desc.clone(), result.clone(), duration));
#![feature(native_link_modifiers_bundle)]
#![feature(nll)]
#![feature(staged_api)]
-#![feature(static_nobundle)]
#![feature(c_unwind)]
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
if self.git_version >= distutils.version.LooseVersion("2.11.0"):
update_args.append("--progress")
update_args.append(module)
- run(update_args, cwd=self.rust_root, verbose=self.verbose, exception=True)
+ try:
+ run(update_args, cwd=self.rust_root, verbose=self.verbose, exception=True)
+ except RuntimeError:
+ print("Failed updating submodule. This is probably due to uncommitted local changes.")
+ print('Either stash the changes by running "git stash" within the submodule\'s')
+ print('directory, reset them by running "git reset --hard", or commit them.')
+ print("To reset all submodules' changes run", end=" ")
+ print('"git submodule foreach --recursive git reset --hard".')
+ raise SystemExit(1)
run(["git", "reset", "-q", "--hard"],
cwd=module_path, verbose=self.verbose)
doc::RustByExample,
doc::RustcBook,
doc::CargoBook,
+ doc::Clippy,
doc::EmbeddedBook,
doc::EditionGuide,
),
t!(fs::create_dir_all(&libdir_self_contained));
let mut target_deps = vec![];
- // Copies the CRT objects.
+ // Copies the libc and CRT objects.
//
// rustc historically provides a more self-contained installation for musl targets
// not requiring the presence of a native musl toolchain. For example, it can fall back
let srcdir = builder.musl_libdir(target).unwrap_or_else(|| {
panic!("Target {:?} does not have a \"musl-libdir\" key", target.triple)
});
- for &obj in &["crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
+ for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] {
copy_and_stamp(
builder,
&libdir_self_contained,
panic!("Target {:?} does not have a \"wasi-root\" key", target.triple)
})
.join("lib/wasm32-wasi");
- for &obj in &["crt1-command.o", "crt1-reactor.o"] {
+ for &obj in &["libc.a", "crt1-command.o", "crt1-reactor.o"] {
copy_and_stamp(
builder,
&libdir_self_contained,
"src/tools/rustfmt",
["rustfmt-nightly", "rustfmt-config_proc_macro"],
);
+tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"]);
#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct ErrorIndex {
struct Crate {
name: Interned<String>,
deps: HashSet<Interned<String>>,
- id: String,
path: PathBuf,
}
#[derive(Deserialize)]
struct Package {
- id: String,
name: String,
source: Option<String>,
manifest_path: String,
.filter(|dep| dep.source.is_none())
.map(|dep| INTERNER.intern_string(dep.name))
.collect();
- build.crates.insert(name, Crate { name, id: package.id, deps, path });
+ build.crates.insert(name, Crate { name, deps, path });
}
}
}
+# We need recent curl, OpenSSL and CA certificates, so we can download further
+# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
+# those.
+FROM ubuntu:20.04
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates
+WORKDIR /tmp
+COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
+RUN ./download-openssl-curl.sh
+
# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
# SLES 11 SP4 (glibc 2.11, kernel 3.0).
apt-get install --allow-unauthenticated -y --no-install-recommends \
automake \
bzip2 \
- ca-certificates \
- curl \
file \
g++ \
g++-multilib \
xz-utils \
zlib1g-dev
-# Install new Let's Encrypt root CA certificate and remove the expired one.
-COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt
-RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf
-RUN /usr/sbin/update-ca-certificates
-
ENV PATH=/rustroot/bin:$PATH
ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
# static.rust-lang.org. This'll be used to link into libcurl below (and used
# later as well), so build a copy of OpenSSL with dynamic libraries into our
# generic root.
+COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
RUN ./build-openssl.sh
#
# Note that we also disable a bunch of optional features of curl that we don't
# really need.
+COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh && apt-get remove -y curl
+RUN ./build-curl.sh
+
+# Use up-to-date curl CA bundle
+COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
+ENV CURL_CA_BUNDLE /tmp/cacert.pem
# binutils < 2.22 has a bug where the 32-bit executables it generates
# immediately segfault in Rust, so we need to install our own binutils.
+# We need recent curl, OpenSSL and CA certificates, so we can download further
+# dependencies in the debian:6 image. We use an ubuntu 20.04 image download
+# those.
+FROM ubuntu:20.04
+RUN apt-get update && \
+ apt-get install -y --no-install-recommends \
+ curl \
+ ca-certificates
+WORKDIR /tmp
+COPY host-x86_64/dist-x86_64-linux/download-openssl-curl.sh /tmp/
+RUN ./download-openssl-curl.sh
+
# We use Debian 6 (glibc 2.11, kernel 2.6.32) as a common base for other
# distros that still need Rust support: RHEL 6 (glibc 2.12, kernel 2.6.32) and
# SLES 11 SP4 (glibc 2.11, kernel 3.0).
apt-get install --allow-unauthenticated -y --no-install-recommends \
automake \
bzip2 \
- ca-certificates \
- curl \
file \
g++ \
g++-multilib \
xz-utils \
zlib1g-dev
-# Install new Let's Encrypt root CA certificate and remove the expired one.
-COPY host-x86_64/shared/ISRG_Root_X1.crt /usr/local/share/ca-certificates/ISRG_Root_X1.crt
-RUN sed -i '/mozilla\/DST_Root_CA_X3\.crt/d' /etc/ca-certificates.conf
-RUN /usr/sbin/update-ca-certificates
-
ENV PATH=/rustroot/bin:$PATH
ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
# static.rust-lang.org. This'll be used to link into libcurl below (and used
# later as well), so build a copy of OpenSSL with dynamic libraries into our
# generic root.
+COPY --from=0 /tmp/openssl.tar.gz /tmp/openssl.tar.gz
COPY host-x86_64/dist-x86_64-linux/build-openssl.sh /tmp/
RUN ./build-openssl.sh
#
# Note that we also disable a bunch of optional features of curl that we don't
# really need.
+COPY --from=0 /tmp/curl.tar.xz /tmp/curl.tar.xz
COPY host-x86_64/dist-x86_64-linux/build-curl.sh /tmp/
-RUN ./build-curl.sh && apt-get remove -y curl
+RUN ./build-curl.sh
+
+# Use up-to-date curl CA bundle
+COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
+ENV CURL_CA_BUNDLE /tmp/cacert.pem
# binutils < 2.22 has a bug where the 32-bit executables it generates
# immediately segfault in Rust, so we need to install our own binutils.
set -ex
source shared.sh
-VERSION=7.66.0
-
-# This needs to be downloaded directly from S3, it can't go through the CDN.
-# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1
-# (without paying an absurd amount of money).
-curl https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/curl-$VERSION.tar.xz \
- | xz --decompress \
- | tar xf -
+tar xJf curl.tar.xz
mkdir curl-build
cd curl-build
-hide_output ../curl-$VERSION/configure \
+hide_output ../curl-*/configure \
--prefix=/rustroot \
--with-ssl=/rustroot \
--disable-sspi \
cd ..
rm -rf curl-build
-rm -rf curl-$VERSION
+rm -rf curl-*
set -ex
source shared.sh
-VERSION=1.0.2k
+tar xzf openssl.tar.gz
-# This needs to be downloaded directly from S3, it can't go through the CDN.
-# That's because the CDN is backed by CloudFront, which requires SNI and TLSv1
-# (without paying an absurd amount of money).
-URL=https://rust-lang-ci-mirrors.s3-us-west-1.amazonaws.com/rustc/openssl-$VERSION.tar.gz
-
-curl $URL | tar xzf -
-
-cd openssl-$VERSION
+cd openssl-*
hide_output ./config --prefix=/rustroot shared -fPIC
hide_output make -j$(nproc)
hide_output make install
cd ..
-rm -rf openssl-$VERSION
+rm -rf openssl-*
# Make the system cert collection available to the new install.
ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/
--- /dev/null
+#!/usr/bin/env bash
+
+set -ex
+
+OPENSSL_VERSION=1.0.2k
+CURL_VERSION=7.66.0
+
+curl -f https://ci-mirrors.rust-lang.org/rustc/openssl-$OPENSSL_VERSION.tar.gz -o openssl.tar.gz
+curl -f https://ci-mirrors.rust-lang.org/rustc/curl-$CURL_VERSION.tar.xz -o curl.tar.xz
+curl -f https://curl.se/ca/cacert.pem -o cacert.pem
+++ /dev/null
------BEGIN CERTIFICATE-----
-MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
-TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
-cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
-WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
-ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
-MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
-h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
-0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
-A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
-T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
-B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
-B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
-KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
-OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
-jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
-qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
-rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
-HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
-hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
-ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
-3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
-NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
-ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
-TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
-jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
-oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
-4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
-mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
-emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
------END CERTIFICATE-----
# Look for all source files involves in the COPY command
copied_files=/tmp/.docker-copied-files.txt
rm -f "$copied_files"
- for i in $(sed -n -e 's/^COPY \(.*\) .*$/\1/p' "$docker_dir/$image/Dockerfile"); do
+ for i in $(sed -n -e '/^COPY --from=/! s/^COPY \(.*\) .*$/\1/p' \
+ "$docker_dir/$image/Dockerfile"); do
# List the file names
find "$script_dir/$i" -type f >> $copied_files
done
for lib in c cxxrt gcc_s m thr util; do
files_to_extract=("${files_to_extract[@]}" "./lib/lib${lib}.*" "./usr/lib/lib${lib}.*")
done
-for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat; do
+for lib in c++ c_nonshared compiler_rt execinfo gcc pthread rt ssp_nonshared procstat kvm; do
files_to_extract=("${files_to_extract[@]}" "./usr/lib/lib${lib}.*")
done
strategy:
matrix:
include:
- - name: dist-x86_64-apple
- env:
- SCRIPT: ./x.py dist --exclude src/doc --exclude extended && ./x.py dist --target=x86_64-apple-darwin src/doc && ./x.py dist extended
- RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --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
-
+ - &dist-x86_64-linux
+ name: dist-x86_64-linux
+ <<: *job-linux-xl
master:
name: master
-Subproject commit eb1282ec444db94055fa9531b6f3f803e86bb382
+Subproject commit fd9299792852c9a368cb236748781852f75cdac6
-Subproject commit 270fccd339e5972d9c900e788f197e81a0bcd956
+Subproject commit 51739471276b1776dea27cf562b974ef07e24685
-Subproject commit 2d66852a27c5d0ec50ae021820d1de22caa2b1bd
+Subproject commit 358e6a61d5f4f0496d0a81e70cdcd25d05307342
-Subproject commit b5c68b02984f74e99d1f1b332029e05f607e2660
+Subproject commit a01d151a7250a540a9cb7ccce5956f020c677c21
-Subproject commit 9a60624fcad0140826c44389571dc622917cd632
+Subproject commit 27f1ff5e440ef78828b68ab882b98e1b10d9af32
-Subproject commit fba15a46ca8efa97e8a955794724ac7ce27805b8
+Subproject commit b06008731af0f7d07cd0614e820c8276dfed1c18
- [Platform Support](platform-support.md)
- [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
- [\*-kmc-solid_\*](platform-support/kmc-solid.md)
+ - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
- [Target Tier Policy](target-tier-policy.md)
- [Targets](targets/index.md)
- [Built-in Targets](targets/built-in.md)
<tr>
<td>Forward-edge control flow protection
</td>
- <td>No
+ <td>Yes
</td>
- <td>
+ <td>Nightly
</td>
</tr>
<tr>
commercially available [grsecurity/PaX Reuse Attack Protector
(RAP)](https://grsecurity.net/rap_faq).
-The Rust compiler does not support forward-edge control flow protection on
-Linux<sup id="fnref:6" role="doc-noteref"><a href="#fn:6"
-class="footnote">6</a></sup>. There is work currently ongoing to add support
-for the [sanitizers](https://github.com/google/sanitizers)[40], which may or
-may not include support for LLVM CFI.
+The Rust compiler supports forward-edge control flow protection on nightly
+builds[40]-[41] <sup id="fnref:6" role="doc-noteref"><a href="#fn:6"
+class="footnote">6</a></sup>.
```text
-$ readelf -s target/release/hello-rust | grep __cfi_init
+$ readelf -s -W target/debug/rust-cfi | grep "\.cfi"
+ 12: 0000000000005170 46 FUNC LOCAL DEFAULT 14 _RNvCsjaOHoaNjor6_8rust_cfi7add_one.cfi
+ 15: 00000000000051a0 16 FUNC LOCAL DEFAULT 14 _RNvCsjaOHoaNjor6_8rust_cfi7add_two.cfi
+ 17: 0000000000005270 396 FUNC LOCAL DEFAULT 14 _RNvCsjaOHoaNjor6_8rust_cfi4main.cfi
+...
```
-Fig. 15. Checking if LLVM CFI is enabled for a given binary.
+Fig. 15. Checking if LLVM CFI is enabled for a given binary[41].
-The presence of the `__cfi_init` symbol (and references to `__cfi_check`)
-indicates that LLVM CFI (i.e., forward-edge control flow protection) is
-enabled for a given binary. Conversely, the absence of the `__cfi_init`
-symbol (and references to `__cfi_check`) indicates that LLVM CFI is not
-enabled for a given binary (see Fig. 15).
+The presence of symbols suffixed with ".cfi" or the `__cfi_init` symbol (and
+references to `__cfi_check`) indicates that LLVM CFI (i.e., forward-edge control
+flow protection) is enabled for a given binary. Conversely, the absence of
+symbols suffixed with ".cfi" or the `__cfi_init` symbol (and references to
+`__cfi_check`) indicates that LLVM CFI is not enabled for a given binary (see
+Fig. 15).
-<small id="fn:6">6\. It supports Control Flow Guard (CFG) on Windows (see
+<small id="fn:6">6\. It also supports Control Flow Guard (CFG) on Windows (see
<https://github.com/rust-lang/rust/issues/68793>). <a href="#fnref:6"
class="reversefootnote" role="doc-backlink">↩</a></small>
39. A. Crichton. “Remove the alloc\_jemalloc crate #55238.” GitHub.
<https://github.com/rust-lang/rust/pull/55238>.
-40. J. Aparicio. 2017. “Tracking issue for sanitizer support #39699.”
- <https://github.com/rust-lang/rust/issues/39699>.
+40. R. de C Valle. “Tracking Issue for LLVM Control Flow Integrity (CFI) Support
+ for Rust #89653.” GitHub. <https://github.com/rust-lang/rust/issues/89653>.
+
+41. “ControlFlowIntegrity.” The Rust Unstable Book.
+ <https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity>.
`x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
`x86_64-unknown-hermit` | ? | |
`x86_64-unknown-l4re-uclibc` | ? | |
+[`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | | Freestanding/bare-metal x86_64, softfloat
`x86_64-unknown-none-hermitkernel` | ? | | HermitCore kernel
`x86_64-unknown-none-linuxkernel` | * | | Linux kernel modules
`x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD
--- /dev/null
+# `x86_64-unknown-none`
+
+**Tier: 3**
+
+Freestanding/bare-metal x86-64 binaries in ELF format: firmware, kernels, etc.
+
+## Target maintainers
+
+- Harald Hoyer `harald@profian.com`, https://github.com/haraldh
+- Mike Leany, https://github.com/mikeleany
+
+## Requirements
+
+This target is cross-compiled. There is no support for `std`. There is no
+default allocator, but it's possible to use `alloc` by supplying an allocator.
+
+By default, Rust code generated for this target does not use any vector or
+floating-point registers (e.g. SSE, AVX). This allows the generated code to run
+in environments, such as kernels, which may need to avoid the use of such
+registers or which may have special considerations about the use of such
+registers (e.g. saving and restoring them to avoid breaking userspace code
+using the same registers). You can change code generation to use additional CPU
+features via the `-C target-feature=` codegen options to rustc, or via the
+`#[target_feature]` mechanism within Rust code.
+
+By default, code generated with this target should run on any `x86_64`
+hardware; enabling additional target features may raise this baseline.
+
+Code generated with this target will use the `kernel` code model by default.
+You can change this using the `-C code-model=` option to rustc.
+
+On `x86_64-unknown-none`, `extern "C"` uses the [standard System V calling
+convention](https://gitlab.com/x86-psABIs/x86-64-ABI), without red zones.
+
+This target generated binaries in the ELF format. Any alternate formats or
+special considerations for binary layout will require linker options or linker
+scripts.
+
+## Building the target
+
+You can build Rust with support for the target by adding it to the `target`
+list in `config.toml`:
+
+```toml
+[build]
+build-stage = 1
+target = ["x86_64-unknown-none"]
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+## Testing
+
+As `x86_64-unknown-none` supports a variety of different environments and does
+not support `std`, this target does not support running the Rust testsuite.
+
+## Cross-compilation toolchains and C code
+
+If you want to compile C code along with Rust (such as for Rust crates with C
+dependencies), you will need an appropriate `x86_64` toolchain.
+
+Rust *may* be able to use an `x86_64-linux-gnu-` toolchain with appropriate
+standalone flags to build for this toolchain (depending on the assumptions of
+that toolchain, see below), or you may wish to use a separate
+`x86_64-unknown-none` (or `x86_64-elf-`) toolchain.
+
+On some `x86_64` hosts that use ELF binaries, you *may* be able to use the host
+C toolchain, if it does not introduce assumptions about the host environment
+that don't match the expectations of a standalone environment. Otherwise, you
+may need a separate toolchain for standalone/freestanding development, just as
+when cross-compiling from a non-`x86_64` platform.
# The Rustdoc Book
- [What is rustdoc?](what-is-rustdoc.md)
+- [How to read rustdoc output](how-to-read-rustdoc.md)
- [How to write documentation](how-to-write-documentation.md)
- [What to include (and exclude)](what-to-include.md)
- [Command-line arguments](command-line-arguments.md)
--- /dev/null
+# How to read rustdoc output
+
+Rustdoc's HTML output includes a friendly and useful navigation interface which
+makes it easier for users to navigate and understand your code.
+This chapter covers the major features of that interface,
+and is a great starting point for documentation authors and users alike.
+
+## Structure
+
+The `rustdoc` output is divided into three sections.
+Along the left side of each page is a quick navigation bar,
+which shows contextual information about the current entry.
+The rest of the page is taken up by the search interface at the top
+and the documentation for the current item below that.
+
+## The Item Documentation
+
+The majority of the screen is taken up with the documentation text for the item
+currently being viewed.
+At the top is some at-a-glance info and controls:
+
+- the type and name of the item,
+ such as "Struct `std::time::Duration`",
+- a button to copy the item's path to the clipboard,
+ which is a clipboard item
+- a button to collapse or expand the top-level documentation for that item
+ (`[+]` or `[-]`),
+- a link to the source code (`[src]`),
+ if [configured](the-doc-attribute.html#html_no_source),
+ and present (the source may not be available if
+ the documentation was created with `cargo doc --no-deps`),
+- and the version in which the item became stable,
+ if it's a stable item in the standard library.
+
+Below this is the main documentation for the item,
+including a definition or function signature if appropriate,
+followed by a list of fields or variants for Rust types.
+Finally, the page lists associated functions and trait implementations,
+including automatic and blanket implementations that `rustdoc` knows about.
+
+### Navigation
+
+Subheadings, variants, fields, and many other things in this documentation
+are anchors and can be clicked on and deep-linked to,
+which is a great way to communicate exactly what you're talking about.
+The typograpical character "§" appears next to lines with anchors on them
+when hovered or given keyboard focus.
+
+## The Navigation Bar
+
+For example, when looking at documentation for the crate root,
+it shows all the crates documented in the documentation bundle,
+and quick links to the modules, structs, traits, functions, and macros available
+from the current crate.
+At the top, it displays a [configurable logo](the-doc-attribute.html#html_logo_url)
+alongside the current crate's name and version,
+or the current item whose documentation is being displayed.
+
+## The Theme Picker and Search Interface
+
+When viewing `rustdoc`'s output in a browser with JavaScript enabled,
+a dynamic interface appears at the top of the page.
+To the left is the theme picker, denoted with a paint-brush icon,
+and the search interface, help screen, and options appear to the right of that.
+
+### The Theme Picker
+
+Clicking on the theme picker provides a list of themes -
+by default `ayu`, `light`, and `dark` -
+which are available for viewing.
+
+### The Search Interface
+
+Typing in the search bar instantly searches the available documentation for
+the string entered with a fuzzy matching algorithm that is tolerant of minor
+typos.
+
+By default, the search results give are "In Names",
+meaning that the fuzzy match is made against the names of items.
+Matching names are shown on the left, and the first few words of their
+descriptions are given on the right.
+By clicking an item, you will navigate to its particular documentation.
+
+There are two other sets of results, shown as tabs in the search results pane.
+"In Parameters" shows matches for the string in the types of parameters to
+functions, and "In Return Types" shows matches in the return types of functions.
+Both are very useful when looking for a function whose name you can't quite
+bring to mind when you know the type you have or want.
+
+When typing in the search bar, you can prefix your search term with a type
+followed by a colon (such as `mod:`) to restrict the results to just that
+kind of item. (The available items are listed in the help popup.)
+
+### Shortcuts
+
+Pressing `S` while focused elsewhere on the page will move focus to the
+search bar, and pressing `?` shows the help screen,
+which includes all these shortcuts and more.
+Pressing `T` focuses the theme picker.
+
+When the search results are focused,
+the left and right arrows move between tabs and the up and down arrows move
+among the results.
+Pressing the enter or return key opens the highlighted result.
+
+When looking at the documentation for an item, the plus and minus keys expand
+and collapse all sections in the document.
These forms of the `#[doc]` attribute are used on individual items, to control how
they are documented.
-## `#[doc(no_inline)]`/`#[doc(inline)]`
+### `inline` and `no_inline`
+
+<span id="docno_inlinedocinline"></span>
These attributes are used on `use` statements, and control where the documentation shows
up. For example, consider this Rust code:
One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will
not eagerly inline it as a module unless you add `#[doc(inline)]`.
-## `#[doc(hidden)]`
+### `hidden`
+
+<span id="dochidden"></span>
Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless
the `strip-hidden` pass is removed.
+
+### `alias`
+
+This attribute adds an alias in the search index.
+
+Let's take an example:
+
+```rust,no_run
+#[doc(alias = "TheAlias")]
+pub struct SomeType;
+```
+
+So now, if you enter "TheAlias" in the search, it'll display `SomeType`.
+Of course, if you enter `SomeType` it'll return `SomeType` as expected!
+
+#### FFI example
+
+This doc attribute is especially useful when writing bindings for a C library.
+For example, let's say we have a C function that looks like this:
+
+```c
+int lib_name_do_something(Obj *obj);
+```
+
+It takes a pointer to an `Obj` type and returns an integer. In Rust, it might
+be written like this:
+
+```ignore (using non-existing ffi types)
+pub struct Obj {
+ inner: *mut ffi::Obj,
+}
+
+impl Obj {
+ pub fn do_something(&mut self) -> i32 {
+ unsafe { ffi::lib_name_do_something(self.inner) }
+ }
+}
+```
+
+The function has been turned into a method to make it more convenient to use.
+However, if you want to look for the Rust equivalent of `lib_name_do_something`,
+you have no way to do so.
+
+To get around this limitation, we just add `#[doc(alias = "lib_name_do_something")]`
+on the `do_something` method and then it's all good!
+Users can now look for `lib_name_do_something` in our crate directly and find
+`Obj::do_something`.
## Document primitives
+This is for Rust compiler internal use only.
+
Since primitive types are defined in the compiler, there's no place to attach documentation
-attributes. The `#[doc(primitive)]` attribute is used by the standard library to provide a way to generate
-documentation for primitive types, and requires `#![feature(doc_primitive)]` to enable.
+attributes. The `#[doc(primitive)]` attribute is used by the standard library to provide a way
+to generate documentation for primitive types, and requires `#![feature(doc_primitive)]` to enable.
+
+## Document keywords
+
+This is for Rust compiler internal use only.
+
+Rust keywords are documented in the standard library (look for `match` for example).
+
+To do so, the `#[doc(keyword = "...")]` attribute is used. Example:
+
+```rust
+#![feature(doc_keyword)]
+
+/// Some documentation about the keyword.
+#[doc(keyword = "keyword")]
+mod empty_mod {}
+```
## Unstable command-line arguments
--- /dev/null
+# `no-unique-section-names`
+
+------------------------
+
+This flag currently applies only to ELF-based targets using the LLVM codegen backend. It prevents the generation of unique ELF section names for each separate code and data item when `-Z function-sections` is also in use, which is the default for most targets. This option can reduce the size of object files, and depending on the linker, the final ELF binary as well.
+
+For example, a function `func` will by default generate a code section called `.text.func`. Normally this is fine because the linker will merge all those `.text.*` sections into a single one in the binary. However, starting with [LLVM 12](https://github.com/llvm/llvm-project/commit/ee5d1a04), the backend will also generate unique section names for exception handling, so you would see a section name of `.gcc_except_table.func` in the object file and potentially in the final ELF binary, which could add significant bloat to programs that contain many functions.
+
+This flag instructs LLVM to use the same `.text` and `.gcc_except_table` section name for each function, and it is analogous to Clang's `-fno-unique-section-names` option.
# `sanitizer`
-The tracking issue for this feature is: [#39699](https://github.com/rust-lang/rust/issues/39699).
+The tracking issues for this feature are:
+
+* [#39699](https://github.com/rust-lang/rust/issues/39699).
+* [#89653](https://github.com/rust-lang/rust/issues/89653).
------------------------
This feature allows for use of one of following sanitizers:
* [AddressSanitizer][clang-asan] a fast memory error detector.
+* [ControlFlowIntegrity][clang-cfi] LLVM Control Flow Integrity (CFI) provides
+ forward-edge control flow protection.
* [HWAddressSanitizer][clang-hwasan] a memory error detector similar to
AddressSanitizer, but based on partial hardware assistance.
* [LeakSanitizer][clang-lsan] a run-time memory leak detector.
* [MemorySanitizer][clang-msan] a detector of uninitialized reads.
* [ThreadSanitizer][clang-tsan] a fast data race detector.
-To enable a sanitizer compile with `-Zsanitizer=address`,
+To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`,
`-Zsanitizer=hwaddress`, `-Zsanitizer=leak`, `-Zsanitizer=memory` or
`-Zsanitizer=thread`.
==39249==ABORTING
```
+# ControlFlowIntegrity
+
+The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially
+provides forward-edge control flow protection for Rust-compiled code only by
+aggregating function pointers in groups identified by their number of arguments.
+
+Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed
+binaries" (i.e., for when C or C++ and Rust -compiled code share the same
+virtual address space) will be provided in later work by defining and using
+compatible type identifiers (see Type metadata in the design document in the
+tracking issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
+
+LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).
+
+## Example
+
+```text
+#![feature(asm, naked_functions)]
+
+use std::mem;
+
+fn add_one(x: i32) -> i32 {
+ x + 1
+}
+
+#[naked]
+pub extern "C" fn add_two(x: i32) {
+ // x + 2 preceeded by a landing pad/nop block
+ unsafe {
+ asm!(
+ "
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ lea rax, [rdi+2]
+ ret
+ ",
+ options(noreturn)
+ );
+ }
+}
+
+fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
+ f(arg) + f(arg)
+}
+
+fn main() {
+ let answer = do_twice(add_one, 5);
+
+ println!("The answer is: {}", answer);
+
+ println!("With CFI enabled, you should not see the next answer");
+ let f: fn(i32) -> i32 = unsafe {
+ // Offsets 0-8 make it land in the landing pad/nop block, and offsets 1-8 are
+ // invalid branch/call destinations (i.e., within the body of the function).
+ mem::transmute::<*const u8, fn(i32) -> i32>((add_two as *const u8).offset(5))
+ };
+ let next_answer = do_twice(f, 5);
+
+ println!("The next answer is: {}", next_answer);
+}
+```
+Fig. 1. Modified example from the [Advanced Functions and
+Closures][rust-book-ch19-05] chapter of the [The Rust Programming
+Language][rust-book] book.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+The next answer is: 14
+$
+```
+Fig. 2. Build and execution of the modified example with LLVM CFI disabled.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+Illegal instruction
+$
+```
+Fig. 3. Build and execution of the modified example with LLVM CFI enabled.
+
+When LLVM CFI is enabled, if there are any attempts to change/hijack control
+flow using an indirect branch/call to an invalid destination, the execution is
+terminated (see Fig. 3).
+
+```rust
+use std::mem;
+
+fn add_one(x: i32) -> i32 {
+ x + 1
+}
+
+fn add_two(x: i32, _y: i32) -> i32 {
+ x + 2
+}
+
+fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
+ f(arg) + f(arg)
+}
+
+fn main() {
+ let answer = do_twice(add_one, 5);
+
+ println!("The answer is: {}", answer);
+
+ println!("With CFI enabled, you should not see the next answer");
+ let f: fn(i32) -> i32 =
+ unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
+ let next_answer = do_twice(f, 5);
+
+ println!("The next answer is: {}", next_answer);
+}
+```
+Fig. 4. Another modified example from the [Advanced Functions and
+Closures][rust-book-ch19-05] chapter of the [The Rust Programming
+Language][rust-book] book.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+The next answer is: 14
+$
+```
+Fig. 5. Build and execution of the modified example with LLVM CFI disabled.
+
+[//]: # (FIXME: Replace with output from cargo using nightly when #89652 is merged)
+
+```shell
+$ rustc -Clto -Zsanitizer=cfi rust_cfi.rs -o rust_cfi
+$ ./rust_cfi
+The answer is: 12
+With CFI enabled, you should not see the next answer
+Illegal instruction
+$
+```
+Fig. 6. Build and execution of the modified example with LLVM CFI enabled.
+
+When LLVM CFI is enabled, if there are any attempts to change/hijack control
+flow using an indirect branch/call to a function with different number of
+arguments than intended/passed in the call/branch site, the execution is also
+terminated (see Fig. 6).
+
+Forward-edge control flow protection not only by aggregating function pointers
+in groups identified by their number of arguments, but also their argument
+types, will also be provided in later work by defining and using compatible type
+identifiers (see Type metadata in the design document in the tracking
+issue [#89653](https://github.com/rust-lang/rust/issues/89653)).
+
+[rust-book-ch19-05]: https://doc.rust-lang.org/book/ch19-05-advanced-functions-and-closures.html
+[rust-book]: https://doc.rust-lang.org/book/title-page.html
+
# HWAddressSanitizer
HWAddressSanitizer is a newer variant of AddressSanitizer that consumes much
* [Sanitizers project page](https://github.com/google/sanitizers/wiki/)
* [AddressSanitizer in Clang][clang-asan]
+* [ControlFlowIntegrity in Clang][clang-cfi]
* [HWAddressSanitizer in Clang][clang-hwasan]
* [LeakSanitizer in Clang][clang-lsan]
* [MemorySanitizer in Clang][clang-msan]
* [ThreadSanitizer in Clang][clang-tsan]
[clang-asan]: https://clang.llvm.org/docs/AddressSanitizer.html
+[clang-cfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html
[clang-hwasan]: https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
[clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
[clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html
This will write the value `5` into the `u64` variable `x`.
You can see that the string literal we use to specify instructions is actually a template string.
It is governed by the same rules as Rust [format strings][format-syntax].
-The arguments that are inserted into the template however look a bit different then you may
+The arguments that are inserted into the template however look a bit different than you may
be familiar with. First we need to specify if the variable is an input or an output of the
inline assembly. In this case it is an output. We declared this by writing `out`.
We also need to specify in what kind of register the assembly expects the variable.
Second, we can see that inputs are declared by writing `in` instead of `out`.
Third, one of our operands has a type we haven't seen yet, `const`.
-This tells the compiler to expand this argument to value directly inside the assembly template.
+This tells the compiler to expand this argument to a value directly inside the assembly template.
This is only possible for constants and literals.
Fourth, we can see that we can specify an argument number, or name as in any format string.
}
println!(
- "L1 Cache: {}",
+ "L0 Cache: {}",
((ebx >> 22) + 1) * (((ebx >> 12) & 0x3ff) + 1) * ((ebx & 0xfff) + 1) * (ecx + 1)
);
```
- You are responsible for switching any target-specific state (e.g. thread-local storage, stack bounds).
- The set of memory locations that you may access is the intersection of those allowed by the `asm!` blocks you entered and exited.
- You cannot assume that an `asm!` block will appear exactly once in the output binary. The compiler is allowed to instantiate multiple copies of the `asm!` block, for example when the function containing it is inlined in multiple places.
+- On x86, inline assembly must not end with an instruction prefix (such as `LOCK`) that would apply to instructions generated by the compiler.
+ - The compiler is currently unable to detect this due to the way inline assembly is compiled, but may catch and reject this in the future.
> **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call.
constants defined in Rust to be used in assembly code:
```rust,no_run
-#![feature(global_asm)]
+#![feature(global_asm, asm_const)]
# #[cfg(any(target_arch="x86", target_arch="x86_64"))]
# mod x86 {
const C: i32 = 1234;
arguments list:
```rust,no_run
-#![feature(global_asm)]
+#![feature(global_asm, asm_const)]
# #[cfg(any(target_arch="x86", target_arch="x86_64"))]
# mod x86 {
global_asm!("movl ${}, %ecx", const 5, options(att_syntax));
arrayvec = { version = "0.7", default-features = false }
pulldown-cmark = { version = "0.8", default-features = false }
minifier = "0.0.41"
-rayon = { version = "0.3.0", package = "rustc-rayon" }
+rayon = "1.3.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
smallvec = "1.6.1"
new_generics
});
- let negative_polarity;
+ let polarity;
let new_generics = match result {
AutoTraitResult::PositiveImpl(new_generics) => {
- negative_polarity = false;
+ polarity = ty::ImplPolarity::Positive;
if discard_positive_impl {
return None;
}
new_generics
}
AutoTraitResult::NegativeImpl => {
- negative_polarity = true;
+ polarity = ty::ImplPolarity::Negative;
// For negative impls, we use the generic params, but *not* the predicates,
// from the original type. Otherwise, the displayed impl appears to be a
visibility: Inherited,
def_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
kind: box ImplItem(Impl {
- span: Span::dummy(),
unsafety: hir::Unsafety::Normal,
generics: new_generics,
trait_: Some(trait_ref.clean(self.cx)),
for_: ty.clean(self.cx),
items: Vec::new(),
- negative_polarity,
- synthetic: true,
- blanket_impl: None,
+ polarity,
+ kind: ImplKind::Auto,
}),
cfg: None,
})
let f = auto_trait::AutoTraitFinder::new(tcx);
debug!("get_auto_trait_impls({:?})", ty);
- let auto_traits: Vec<_> = self.cx.auto_traits.iter().cloned().collect();
+ let auto_traits: Vec<_> = self.cx.auto_traits.iter().copied().collect();
let mut auto_traits: Vec<Item> = auto_traits
.into_iter()
.filter_map(|trait_def_id| {
// to its smaller and larger regions. Note that 'larger' regions correspond
// to sub-regions in Rust code (e.g., in 'a: 'b, 'a is the larger region).
for constraint in regions.constraints.keys() {
- match constraint {
- &Constraint::VarSubVar(r1, r2) => {
+ match *constraint {
+ Constraint::VarSubVar(r1, r2) => {
{
let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default();
deps1.larger.insert(RegionTarget::RegionVid(r2));
let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default();
deps2.smaller.insert(RegionTarget::RegionVid(r1));
}
- &Constraint::RegSubVar(region, vid) => {
+ Constraint::RegSubVar(region, vid) => {
let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
deps.smaller.insert(RegionTarget::Region(region));
}
- &Constraint::VarSubReg(vid, region) => {
+ Constraint::VarSubReg(vid, region) => {
let deps = vid_map.entry(RegionTarget::RegionVid(vid)).or_default();
deps.larger.insert(RegionTarget::Region(region));
}
- &Constraint::RegSubReg(r1, r2) => {
+ Constraint::RegSubReg(r1, r2) => {
// The constraint is already in the form that we want, so we're done with it
// Desired order is 'larger, smaller', so flip then
if region_name(r1) != region_name(r2) {
// as we want to combine them with any 'Output' qpaths
// later
- let is_fn = match &mut b {
- &mut GenericBound::TraitBound(ref mut p, _) => {
+ let is_fn = match b {
+ GenericBound::TraitBound(ref mut p, _) => {
// Insert regions into the for_generics hash map first, to ensure
// that we don't end up with duplicate bounds (e.g., for<'b, 'b>)
for_generics.extend(p.generic_params.clone());
}
fn region_name(region: Region<'_>) -> Option<Symbol> {
- match region {
- &ty::ReEarlyBound(r) => Some(r.name),
+ match *region {
+ ty::ReEarlyBound(r) => Some(r.name),
_ => None,
}
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- (match r {
- &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
+ (match *r {
+ ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
_ => None,
})
.unwrap_or_else(|| r.super_fold_with(self))
visibility: Inherited,
def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
kind: box ImplItem(Impl {
- span: Span::new(self.cx.tcx.def_span(impl_def_id)),
unsafety: hir::Unsafety::Normal,
generics: (
self.cx.tcx.generics_of(impl_def_id),
.tcx
.associated_items(impl_def_id)
.in_definition_order()
- .collect::<Vec<_>>()
- .clean(self.cx),
- negative_polarity: false,
- synthetic: false,
- blanket_impl: Some(box trait_ref.self_ty().clean(self.cx)),
+ .map(|x| x.clean(self.cx))
+ .collect::<Vec<_>>(),
+ polarity: ty::ImplPolarity::Positive,
+ kind: ImplKind::Blanket(box trait_ref.self_ty().clean(self.cx)),
}),
cfg: None,
});
use rustc_span::symbol::{kw, sym, Symbol};
use crate::clean::{
- self, utils, Attributes, AttributesExt, GetDefId, ItemId, NestedAttributesExt, Type,
+ self, utils, Attributes, AttributesExt, ImplKind, ItemId, NestedAttributesExt, Type,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
clean::Enum {
generics: (cx.tcx.generics_of(did), predicates).clean(cx),
variants_stripped: false,
- variants: cx.tcx.adt_def(did).variants.clean(cx),
+ variants: cx.tcx.adt_def(did).variants.iter().map(|v| v.clean(cx)).collect(),
}
}
clean::Struct {
struct_type: variant.ctor_kind,
generics: (cx.tcx.generics_of(did), predicates).clean(cx),
- fields: variant.fields.clean(cx),
+ fields: variant.fields.iter().map(|x| x.clean(cx)).collect(),
fields_stripped: false,
}
}
let predicates = cx.tcx.explicit_predicates_of(did);
let variant = cx.tcx.adt_def(did).non_enum_variant();
- clean::Union {
- generics: (cx.tcx.generics_of(did), predicates).clean(cx),
- fields: variant.fields.clean(cx),
- fields_stripped: false,
- }
+ let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
+ let fields = variant.fields.iter().map(|x| x.clean(cx)).collect();
+ clean::Union { generics, fields, fields_stripped: false }
}
fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::Typedef {
}
}
-/// Builds a specific implementation of a type. The `did` could be a type method or trait method.
+/// Inline an `impl`, inherent or of a trait. The `did` must be for an `impl`.
crate fn build_impl(
cx: &mut DocContext<'_>,
parent_module: impl Into<Option<DefId>>,
return;
}
+ let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impl");
+
let tcx = cx.tcx;
let associated_trait = tcx.impl_trait_ref(did);
// Only inline impl if the implementing type is
// reachable in rustdoc generated documentation
if !did.is_local() {
- if let Some(did) = for_.def_id() {
+ if let Some(did) = for_.def_id(&cx.cache) {
if !cx.cache.access_levels.is_public(did) {
return;
}
),
};
let polarity = tcx.impl_polarity(did);
- let trait_ = associated_trait.clean(cx);
+ let trait_ = associated_trait.map(|t| t.clean(cx));
if trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait() {
super::build_deref_target_impls(cx, &trait_items, ret);
}
}
while let Some(ty) = stack.pop() {
- if let Some(did) = ty.def_id() {
+ if let Some(did) = ty.def_id(&cx.cache) {
if tcx.get_attrs(did).lists(sym::doc).has_word(sym::hidden) {
return;
}
let (merged_attrs, cfg) = merge_attrs(cx, parent_module.into(), load_attrs(cx, did), attrs);
trace!("merged_attrs={:?}", merged_attrs);
- trace!("build_impl: impl {:?} for {:?}", trait_.as_ref().map(|t| t.def_id()), for_.def_id());
+ trace!(
+ "build_impl: impl {:?} for {:?}",
+ trait_.as_ref().map(|t| t.def_id()),
+ for_.def_id(&cx.cache)
+ );
ret.push(clean::Item::from_def_id_and_attrs_and_parts(
did,
None,
clean::ImplItem(clean::Impl {
- span: clean::types::rustc_span(did, cx.tcx),
unsafety: hir::Unsafety::Normal,
generics,
trait_,
for_,
items: trait_items,
- negative_polarity: polarity.clean(cx),
- synthetic: false,
- blanket_impl: None,
+ polarity,
+ kind: ImplKind::Normal,
}),
box merged_attrs,
cx,
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
-use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::fold::TypeFolder;
use std::collections::hash_map::Entry;
use std::default::Default;
use std::hash::Hash;
-use std::rc::Rc;
use std::{mem, vec};
use crate::core::{self, DocContext, ImplTraitParam};
fn clean(&self, cx: &mut DocContext<'_>) -> T;
}
-impl<T: Clean<U>, U> Clean<Vec<U>> for [T] {
- fn clean(&self, cx: &mut DocContext<'_>) -> Vec<U> {
- self.iter().map(|x| x.clean(cx)).collect()
- }
-}
-
-impl<T: Clean<U>, U, V: Idx> Clean<IndexVec<V, U>> for IndexVec<V, T> {
- fn clean(&self, cx: &mut DocContext<'_>) -> IndexVec<V, U> {
- self.iter().map(|x| x.clean(cx)).collect()
- }
-}
-
-impl<T: Clean<U>, U> Clean<U> for &T {
- fn clean(&self, cx: &mut DocContext<'_>) -> U {
- (**self).clean(cx)
- }
-}
-
-impl<T: Clean<U>, U> Clean<U> for Rc<T> {
- fn clean(&self, cx: &mut DocContext<'_>) -> U {
- (**self).clean(cx)
- }
-}
-
-impl<T: Clean<U>, U> Clean<Option<U>> for Option<T> {
- fn clean(&self, cx: &mut DocContext<'_>) -> Option<U> {
- self.as_ref().map(|v| v.clean(cx))
- }
-}
-
impl Clean<Item> for doctree::Module<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let mut items: Vec<Item> = vec![];
impl Clean<Lifetime> for hir::Lifetime {
fn clean(&self, cx: &mut DocContext<'_>) -> Lifetime {
let def = cx.tcx.named_region(self.hir_id);
- match def {
- Some(
- rl::Region::EarlyBound(_, node_id, _)
- | rl::Region::LateBound(_, _, node_id, _)
- | rl::Region::Free(_, node_id),
- ) => {
- if let Some(lt) = cx.lt_substs.get(&node_id).cloned() {
- return lt;
- }
+ if let Some(
+ rl::Region::EarlyBound(_, node_id, _)
+ | rl::Region::LateBound(_, _, node_id, _)
+ | rl::Region::Free(_, node_id),
+ ) = def
+ {
+ if let Some(lt) = cx.substs.get(&node_id).and_then(|p| p.as_lt()).cloned() {
+ return lt;
}
- _ => {}
}
Lifetime(self.name.ident().name)
}
.collect();
WherePredicate::BoundPredicate {
ty: wbp.bounded_ty.clean(cx),
- bounds: wbp.bounds.clean(cx),
+ bounds: wbp.bounds.iter().map(|x| x.clean(cx)).collect(),
bound_params,
}
}
hir::WherePredicate::RegionPredicate(ref wrp) => WherePredicate::RegionPredicate {
lifetime: wrp.lifetime.clean(cx),
- bounds: wrp.bounds.clean(cx),
+ bounds: wrp.bounds.iter().map(|x| x.clean(cx)).collect(),
},
hir::WherePredicate::EqPredicate(ref wrp) => {
let self_type = self.self_ty().clean(cx);
Type::QPath {
name: cx.tcx.associated_item(self.item_def_id).ident.name,
- self_def_id: self_type.def_id(),
+ self_def_id: self_type.def_id(&cx.cache),
self_type: box self_type,
trait_,
}
self.name.ident().name,
GenericParamDefKind::Type {
did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
- bounds: self.bounds.clean(cx),
- default: default.clean(cx).map(Box::new),
+ bounds: self.bounds.iter().map(|x| x.clean(cx)).collect(),
+ default: default.map(|t| t.clean(cx)).map(Box::new),
synthetic,
},
),
}
params.extend(impl_trait_params);
- let mut generics =
- Generics { params, where_predicates: self.where_clause.predicates.clean(cx) };
+ let mut generics = Generics {
+ params,
+ where_predicates: self.where_clause.predicates.iter().map(|x| x.clean(cx)).collect(),
+ };
// Some duplicates are generated for ?Sized bounds between type params and where
// predicates. The point in here is to move the bounds definitions from type params
.iter()
.enumerate()
.map(|(i, ty)| Argument {
- name: name_from_pat(&body.params[i].pat),
+ name: name_from_pat(body.params[i].pat),
type_: ty.clean(cx),
})
.collect(),
fn clean(&self, cx: &mut DocContext<'_>) -> PolyTrait {
PolyTrait {
trait_: self.trait_ref.clean(cx),
- generic_params: self.bound_generic_params.clean(cx),
+ generic_params: self.bound_generic_params.iter().map(|x| x.clean(cx)).collect(),
}
}
}
}
MethodItem(m, None)
}
- hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(ref names)) => {
+ hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
let (generics, decl) = enter_impl_trait(cx, |cx| {
- (self.generics.clean(cx), (&*sig.decl, &names[..]).clean(cx))
+ (self.generics.clean(cx), (sig.decl, names).clean(cx))
});
let mut t = Function { header: sig.header, decl, generics };
if t.header.constness == hir::Constness::Const
}
TyMethodItem(t)
}
- hir::TraitItemKind::Type(ref bounds, ref default) => {
- AssocTypeItem(bounds.clean(cx), default.clean(cx))
+ hir::TraitItemKind::Type(bounds, ref default) => {
+ let bounds = bounds.iter().map(|x| x.clean(cx)).collect();
+ let default = default.map(|t| t.clean(cx));
+ AssocTypeItem(bounds, default)
}
};
let what_rustc_thinks =
None
};
- AssocTypeItem(bounds, ty.clean(cx))
+ AssocTypeItem(bounds, ty.map(|t| t.clean(cx)))
} else {
// FIXME: when could this happen? Associated items in inherent impls?
let type_ = tcx.type_of(self.def_id).clean(cx);
}
fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type {
- use rustc_hir::GenericParamCount;
let hir::Ty { hir_id: _, span, ref kind } = *hir_ty;
let qpath = match kind {
hir::TyKind::Path(qpath) => qpath,
match qpath {
hir::QPath::Resolved(None, ref path) => {
if let Res::Def(DefKind::TyParam, did) = path.res {
- if let Some(new_ty) = cx.ty_substs.get(&did).cloned() {
+ if let Some(new_ty) = cx.substs.get(&did).and_then(|p| p.as_ty()).cloned() {
return new_ty;
}
if let Some(bounds) = cx.impl_trait_bounds.remove(&did.into()) {
}
}
- let mut alias = None;
- if let Res::Def(DefKind::TyAlias, def_id) = path.res {
- // Substitute private type aliases
- if let Some(def_id) = def_id.as_local() {
- let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
- if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
- alias = Some(&cx.tcx.hir().expect_item(hir_id).kind);
- }
- }
- };
-
- if let Some(&hir::ItemKind::TyAlias(ref ty, ref generics)) = alias {
- let provided_params = &path.segments.last().expect("segments were empty");
- let mut ty_substs = FxHashMap::default();
- let mut lt_substs = FxHashMap::default();
- let mut ct_substs = FxHashMap::default();
- let generic_args = provided_params.args();
- {
- let mut indices: GenericParamCount = Default::default();
- for param in generics.params.iter() {
- match param.kind {
- hir::GenericParamKind::Lifetime { .. } => {
- let mut j = 0;
- let lifetime = generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Lifetime(lt) => {
- if indices.lifetimes == j {
- return Some(lt);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(lt) = lifetime.cloned() {
- let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let cleaned = if !lt.is_elided() {
- lt.clean(cx)
- } else {
- self::types::Lifetime::elided()
- };
- lt_substs.insert(lt_def_id.to_def_id(), cleaned);
- }
- indices.lifetimes += 1;
- }
- hir::GenericParamKind::Type { ref default, .. } => {
- let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let mut j = 0;
- let type_ = generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Type(ty) => {
- if indices.types == j {
- return Some(ty);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(ty) = type_ {
- ty_substs.insert(ty_param_def_id.to_def_id(), ty.clean(cx));
- } else if let Some(default) = *default {
- ty_substs
- .insert(ty_param_def_id.to_def_id(), default.clean(cx));
- }
- indices.types += 1;
- }
- hir::GenericParamKind::Const { .. } => {
- let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- let mut j = 0;
- let const_ = generic_args.args.iter().find_map(|arg| match arg {
- hir::GenericArg::Const(ct) => {
- if indices.consts == j {
- return Some(ct);
- }
- j += 1;
- None
- }
- _ => None,
- });
- if let Some(ct) = const_ {
- ct_substs.insert(const_param_def_id.to_def_id(), ct.clean(cx));
- }
- // FIXME(const_generics_defaults)
- indices.consts += 1;
- }
- }
- }
- }
- return cx.enter_alias(ty_substs, lt_substs, ct_substs, |cx| ty.clean(cx));
+ if let Some(expanded) = maybe_expand_private_type_alias(cx, path) {
+ expanded
+ } else {
+ let path = path.clean(cx);
+ resolve_type(cx, path)
}
- let path = path.clean(cx);
- resolve_type(cx, path)
}
- hir::QPath::Resolved(Some(ref qself), ref p) => {
+ hir::QPath::Resolved(Some(ref qself), p) => {
// Try to normalize `<X as Y>::T` to a type
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
if let Some(normalized_value) = normalize(cx, ty) {
let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id();
let trait_ = self::Path {
res: Res::Def(DefKind::Trait, trait_def),
- segments: trait_segments.clean(cx),
+ segments: trait_segments.iter().map(|x| x.clean(cx)).collect(),
};
register_res(cx, trait_.res);
Type::QPath {
trait_,
}
}
- hir::QPath::TypeRelative(ref qself, ref segment) => {
+ hir::QPath::TypeRelative(ref qself, segment) => {
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
let res = match ty.kind() {
ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id),
}
}
+fn maybe_expand_private_type_alias(cx: &mut DocContext<'_>, path: &hir::Path<'_>) -> Option<Type> {
+ let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
+ // Substitute private type aliases
+ let Some(def_id) = def_id.as_local() else { return None };
+ let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
+ let alias = if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
+ &cx.tcx.hir().expect_item(hir_id).kind
+ } else {
+ return None;
+ };
+ let hir::ItemKind::TyAlias(ty, generics) = alias else { return None };
+
+ let provided_params = &path.segments.last().expect("segments were empty");
+ let mut substs = FxHashMap::default();
+ let generic_args = provided_params.args();
+
+ let mut indices: hir::GenericParamCount = Default::default();
+ for param in generics.params.iter() {
+ match param.kind {
+ hir::GenericParamKind::Lifetime { .. } => {
+ let mut j = 0;
+ let lifetime = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Lifetime(lt) => {
+ if indices.lifetimes == j {
+ return Some(lt);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(lt) = lifetime.cloned() {
+ let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let cleaned = if !lt.is_elided() {
+ lt.clean(cx)
+ } else {
+ self::types::Lifetime::elided()
+ };
+ substs.insert(lt_def_id.to_def_id(), SubstParam::Lifetime(cleaned));
+ }
+ indices.lifetimes += 1;
+ }
+ hir::GenericParamKind::Type { ref default, .. } => {
+ let ty_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let mut j = 0;
+ let type_ = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Type(ty) => {
+ if indices.types == j {
+ return Some(ty);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(ty) = type_ {
+ substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(ty.clean(cx)));
+ } else if let Some(default) = *default {
+ substs.insert(ty_param_def_id.to_def_id(), SubstParam::Type(default.clean(cx)));
+ }
+ indices.types += 1;
+ }
+ hir::GenericParamKind::Const { .. } => {
+ let const_param_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let mut j = 0;
+ let const_ = generic_args.args.iter().find_map(|arg| match arg {
+ hir::GenericArg::Const(ct) => {
+ if indices.consts == j {
+ return Some(ct);
+ }
+ j += 1;
+ None
+ }
+ _ => None,
+ });
+ if let Some(ct) = const_ {
+ substs
+ .insert(const_param_def_id.to_def_id(), SubstParam::Constant(ct.clean(cx)));
+ }
+ // FIXME(const_generics_defaults)
+ indices.consts += 1;
+ }
+ }
+ }
+
+ Some(cx.enter_alias(substs, |cx| ty.clean(cx)))
+}
+
impl Clean<Type> for hir::Ty<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Type {
use rustc_hir::*;
let length = print_const(cx, ct.eval(cx.tcx, param_env));
Array(box ty.clean(cx), length)
}
- TyKind::Tup(ref tys) => Tuple(tys.clean(cx)),
+ TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()),
TyKind::OpaqueDef(item_id, _) => {
let item = cx.tcx.hir().item(item_id);
if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
- ImplTrait(ty.bounds.clean(cx))
+ ImplTrait(ty.bounds.iter().map(|x| x.clean(cx)).collect())
} else {
unreachable!()
}
}
- TyKind::Path(_) => clean_qpath(&self, cx),
- TyKind::TraitObject(ref bounds, ref lifetime, _) => {
+ TyKind::Path(_) => clean_qpath(self, cx),
+ TyKind::TraitObject(bounds, ref lifetime, _) => {
let bounds = bounds.iter().map(|bound| bound.clean(cx)).collect();
let lifetime = if !lifetime.is_elided() { Some(lifetime.clean(cx)) } else { None };
DynTrait(bounds, lifetime)
let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
ResolvedPath { path, did }
}
- ty::Dynamic(ref obj, ref reg) => {
+ ty::Dynamic(obj, ref reg) => {
// HACK: pick the first `did` as the `did` of the trait object. Someone
// might want to implement "native" support for marker-trait-only
// trait objects.
DynTrait(bounds, lifetime)
}
- ty::Tuple(ref t) => {
- Tuple(t.iter().map(|t| t.expect_ty()).collect::<Vec<_>>().clean(cx))
- }
+ ty::Tuple(t) => Tuple(t.iter().map(|t| t.expect_ty().clean(cx)).collect()),
ty::Projection(ref data) => data.clean(cx),
impl Clean<Path> for hir::Path<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> Path {
- Path { res: self.res, segments: self.segments.clean(cx) }
+ Path { res: self.res, segments: self.segments.iter().map(|x| x.clean(cx)).collect() }
}
}
let output = self.bindings[0].ty().clean(cx);
let output =
if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
- GenericArgs::Parenthesized { inputs: self.inputs().clean(cx), output }
+ let inputs = self.inputs().iter().map(|x| x.clean(cx)).collect();
+ GenericArgs::Parenthesized { inputs, output }
} else {
- GenericArgs::AngleBracketed {
- args: self
- .args
- .iter()
- .map(|arg| match arg {
- hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
- GenericArg::Lifetime(lt.clean(cx))
- }
- hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
- hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)),
- hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(ct.clean(cx))),
- hir::GenericArg::Infer(_inf) => GenericArg::Infer,
- })
- .collect(),
- bindings: self.bindings.clean(cx),
- }
+ let args = self
+ .args
+ .iter()
+ .map(|arg| match arg {
+ hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
+ GenericArg::Lifetime(lt.clean(cx))
+ }
+ hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
+ hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)),
+ hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(ct.clean(cx))),
+ hir::GenericArg::Infer(_inf) => GenericArg::Infer,
+ })
+ .collect();
+ let bindings = self.bindings.iter().map(|x| x.clean(cx)).collect();
+ GenericArgs::AngleBracketed { args, bindings }
}
}
}
impl Clean<BareFunctionDecl> for hir::BareFnTy<'_> {
fn clean(&self, cx: &mut DocContext<'_>) -> BareFunctionDecl {
let (generic_params, decl) = enter_impl_trait(cx, |cx| {
- (self.generic_params.clean(cx), (&*self.decl, self.param_names).clean(cx))
+ let generic_params = self.generic_params.iter().map(|x| x.clean(cx)).collect();
+ let decl = (self.decl, self.param_names).clean(cx);
+ (generic_params, decl)
});
BareFunctionDecl { unsafety: self.unsafety, abi: self.abi, decl, generic_params }
}
kind: ConstantKind::Local { body: body_id, def_id },
}),
ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
- bounds: ty.bounds.clean(cx),
+ bounds: ty.bounds.iter().map(|x| x.clean(cx)).collect(),
generics: ty.generics.clean(cx),
}),
ItemKind::TyAlias(hir_ty, ref generics) => {
}),
ItemKind::TraitAlias(ref generics, bounds) => TraitAliasItem(TraitAlias {
generics: generics.clean(cx),
- bounds: bounds.clean(cx),
+ bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
}),
ItemKind::Union(ref variant_data, ref generics) => UnionItem(Union {
generics: generics.clean(cx),
- fields: variant_data.fields().clean(cx),
+ fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
fields_stripped: false,
}),
ItemKind::Struct(ref variant_data, ref generics) => StructItem(Struct {
struct_type: CtorKind::from_hir(variant_data),
generics: generics.clean(cx),
- fields: variant_data.fields().clean(cx),
+ fields: variant_data.fields().iter().map(|x| x.clean(cx)).collect(),
fields_stripped: false,
}),
ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.hir_id(), cx),
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
}
ItemKind::Macro(ref macro_def) => MacroItem(Macro {
- source: display_macro_source(cx, name, ¯o_def, def_id, &item.vis),
+ source: display_macro_source(cx, name, macro_def, def_id, item.vis),
}),
- ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => {
+ ItemKind::Trait(is_auto, unsafety, ref generics, bounds, item_ids) => {
let items = item_ids
.iter()
.map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx))
unsafety,
items,
generics: generics.clean(cx),
- bounds: bounds.clean(cx),
+ bounds: bounds.iter().map(|x| x.clean(cx)).collect(),
is_auto: is_auto.clean(cx),
})
}
}
}
-impl Clean<bool> for ty::ImplPolarity {
- /// Returns whether the impl has negative polarity.
- fn clean(&self, _: &mut DocContext<'_>) -> bool {
- match self {
- &ty::ImplPolarity::Positive |
- // FIXME: do we want to do something else here?
- &ty::ImplPolarity::Reservation => false,
- &ty::ImplPolarity::Negative => true,
- }
- }
-}
-
fn clean_impl(impl_: &hir::Impl<'_>, hir_id: hir::HirId, cx: &mut DocContext<'_>) -> Vec<Item> {
let tcx = cx.tcx;
let mut ret = Vec::new();
- let trait_ = impl_.of_trait.clean(cx);
+ let trait_ = impl_.of_trait.as_ref().map(|t| t.clean(cx));
let items =
impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
let def_id = tcx.hir().local_def_id(hir_id);
}
let for_ = impl_.self_ty.clean(cx);
- let type_alias = for_.def_id().and_then(|did| match tcx.def_kind(did) {
+ let type_alias = for_.def_id(&cx.cache).and_then(|did| match tcx.def_kind(did) {
DefKind::TyAlias => Some(tcx.type_of(did).clean(cx)),
_ => None,
});
let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
let kind = ImplItem(Impl {
- span: types::rustc_span(tcx.hir().local_def_id(hir_id).to_def_id(), tcx),
unsafety: impl_.unsafety,
generics: impl_.generics.clean(cx),
trait_,
for_,
items,
- negative_polarity: tcx.impl_polarity(def_id).clean(cx),
- synthetic: false,
- blanket_impl: None,
+ polarity: tcx.impl_polarity(def_id),
+ kind: ImplKind::Normal,
});
Item::from_hir_id_and_parts(hir_id, None, kind, cx)
};
let def_id = item.def_id.to_def_id();
cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
- hir::ForeignItemKind::Fn(ref decl, ref names, ref generics) => {
+ hir::ForeignItemKind::Fn(decl, names, ref generics) => {
let abi = cx.tcx.hir().get_foreign_abi(item.hir_id());
- let (generics, decl) = enter_impl_trait(cx, |cx| {
- (generics.clean(cx), (&**decl, &names[..]).clean(cx))
- });
+ let (generics, decl) =
+ enter_impl_trait(cx, |cx| (generics.clean(cx), (decl, names).clean(cx)));
ForeignFunctionItem(Function {
decl,
generics,
hir::TypeBindingKind::Equality { ref ty } => {
TypeBindingKind::Equality { ty: ty.clean(cx) }
}
- hir::TypeBindingKind::Constraint { ref bounds } => {
+ hir::TypeBindingKind::Constraint { bounds } => {
TypeBindingKind::Constraint { bounds: bounds.iter().map(|b| b.clean(cx)).collect() }
}
}
}
}
+/// The crate currently being documented.
#[derive(Clone, Debug)]
crate struct Crate {
- crate name: Symbol,
- crate src: FileName,
crate module: Item,
crate externs: Vec<ExternalCrate>,
crate primitives: ThinVec<(DefId, PrimitiveType)>,
crate collapsed: bool,
}
+// `Crate` is frequently moved by-value. Make sure it doesn't unintentionally get bigger.
+#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Crate, 104);
+
+impl Crate {
+ crate fn name(&self, tcx: TyCtxt<'_>) -> Symbol {
+ ExternalCrate::LOCAL.name(tcx)
+ }
+
+ crate fn src(&self, tcx: TyCtxt<'_>) -> FileName {
+ ExternalCrate::LOCAL.src(tcx)
+ }
+}
+
/// This struct is used to wrap additional information added by rustdoc on a `trait` item.
#[derive(Clone, Debug)]
crate struct TraitWithExtraInfo {
}
impl ExternalCrate {
+ const LOCAL: Self = Self { crate_num: LOCAL_CRATE };
+
#[inline]
crate fn def_id(&self) -> DefId {
DefId { krate: self.crate_num, index: CRATE_DEF_INDEX }
.filter_map(|a| a.value_str())
.map(to_remote)
.next()
- .or(extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
+ .or_else(|| extern_url.map(to_remote)) // NOTE: only matters if `extern_url_takes_precedence` is false
.unwrap_or(Unknown) // Well, at least we tried.
}
hir::ItemKind::Mod(_) => {
as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
}
- hir::ItemKind::Use(ref path, hir::UseKind::Single)
+ hir::ItemKind::Use(path, hir::UseKind::Single)
if item.vis.node.is_pub() =>
{
as_keyword(path.res.expect_non_local())
hir::ItemKind::Mod(_) => {
as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
}
- hir::ItemKind::Use(ref path, hir::UseKind::Single)
+ hir::ItemKind::Use(path, hir::UseKind::Single)
if item.vis.node.is_pub() =>
{
as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
ItemKind::StrippedItem(k) => k,
_ => &*self.kind,
};
- if let ItemKind::ModuleItem(Module { span, .. }) | ItemKind::ImplItem(Impl { span, .. }) =
- kind
- {
- *span
- } else {
- self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(|| Span::dummy())
+ match kind {
+ ItemKind::ModuleItem(Module { span, .. }) => *span,
+ ItemKind::ImplItem(Impl { kind: ImplKind::Auto, .. }) => Span::dummy(),
+ ItemKind::ImplItem(Impl { kind: ImplKind::Blanket(_), .. }) => {
+ if let ItemId::Blanket { impl_id, .. } = self.def_id {
+ rustc_span(impl_id, tcx)
+ } else {
+ panic!("blanket impl item has non-blanket ID")
+ }
+ }
+ _ => {
+ self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(Span::dummy)
+ }
}
}
}
crate fn stability_class(&self, tcx: TyCtxt<'_>) -> Option<String> {
- self.stability(tcx).as_ref().and_then(|ref s| {
+ self.stability(tcx).as_ref().and_then(|s| {
let mut classes = Vec::with_capacity(2);
if s.level.is_unstable() {
fn cfg(&self, tcx: TyCtxt<'_>, hidden_cfg: &FxHashSet<Cfg>) -> Option<Arc<Cfg>> {
let sess = tcx.sess;
let doc_cfg_active = tcx.features().doc_cfg;
+ let doc_auto_cfg_active = tcx.features().doc_auto_cfg;
fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
let mut iter = it.into_iter();
Some(item)
}
- let mut cfg = if doc_cfg_active {
+ let mut cfg = if doc_cfg_active || doc_auto_cfg_active {
let mut doc_cfg = self
.iter()
.filter(|attr| attr.has_name(sym::doc))
.flat_map(|attr| attr.meta_item_list().unwrap_or_else(Vec::new))
.filter(|attr| attr.has_name(sym::cfg))
.peekable();
- if doc_cfg.peek().is_some() {
+ if doc_cfg.peek().is_some() && doc_cfg_active {
doc_cfg
.filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
- } else {
+ } else if doc_auto_cfg_active {
self.iter()
.filter(|attr| attr.has_name(sym::cfg))
.filter_map(|attr| single(attr.meta_item_list()?))
.filter_map(|attr| Cfg::parse(attr.meta_item()?).ok())
.filter(|cfg| !hidden_cfg.contains(cfg))
.fold(Cfg::True, |cfg, new_cfg| cfg & new_cfg)
+ } else {
+ Cfg::True
}
} else {
Cfg::True
// #[doc(cfg(...))]
if let Some(cfg_mi) = item
.meta_item()
- .and_then(|item| rustc_expand::config::parse_cfg(&item, sess))
+ .and_then(|item| rustc_expand::config::parse_cfg(item, sess))
{
- match Cfg::parse(&cfg_mi) {
+ match Cfg::parse(cfg_mi) {
Ok(new_cfg) => cfg &= new_cfg,
Err(e) => sess.span_err(e.span, e.msg),
}
T: IntoIterator<Item = &'a DocFragment>,
{
iter.into_iter().fold(String::new(), |mut acc, frag| {
- add_doc_fragment(&mut acc, &frag);
+ add_doc_fragment(&mut acc, frag);
acc
})
}
let ori = iter.next()?;
let mut out = String::new();
- add_doc_fragment(&mut out, &ori);
- while let Some(new_frag) = iter.next() {
+ add_doc_fragment(&mut out, ori);
+ for new_frag in iter {
if new_frag.kind != ori.kind || new_frag.parent_module != ori.parent_module {
break;
}
- add_doc_fragment(&mut out, &new_frag);
+ add_doc_fragment(&mut out, new_frag);
}
if out.is_empty() { None } else { Some(out) }
}
for new_frag in self.doc_strings.iter() {
let out = ret.entry(new_frag.parent_module).or_default();
- add_doc_fragment(out, &new_frag);
+ add_doc_fragment(out, new_frag);
}
ret
}
DefaultReturn,
}
-impl GetDefId for FnRetTy {
- fn def_id(&self) -> Option<DefId> {
- match *self {
- Return(ref ty) => ty.def_id(),
- DefaultReturn => None,
- }
- }
-
- fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
- match *self {
- Return(ref ty) => ty.def_id_full(cache),
+impl FnRetTy {
+ crate fn as_return(&self) -> Option<&Type> {
+ match self {
+ Return(ret) => Some(ret),
DefaultReturn => None,
}
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Type, 72);
-crate trait GetDefId {
- /// Use this method to get the [`DefId`] of a [`clean`] AST node.
- /// This will return [`None`] when called on a primitive [`clean::Type`].
- /// Use [`Self::def_id_full`] if you want to include primitives.
- ///
- /// [`clean`]: crate::clean
- /// [`clean::Type`]: crate::clean::Type
- // FIXME: get rid of this function and always use `def_id_full`
- fn def_id(&self) -> Option<DefId>;
-
- /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
- ///
- /// See [`Self::def_id`] for more.
- ///
- /// [clean]: crate::clean
- fn def_id_full(&self, cache: &Cache) -> Option<DefId>;
-}
-
-impl<T: GetDefId> GetDefId for Option<T> {
- fn def_id(&self) -> Option<DefId> {
- self.as_ref().and_then(|d| d.def_id())
- }
-
- fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
- self.as_ref().and_then(|d| d.def_id_full(cache))
- }
-}
-
impl Type {
crate fn primitive_type(&self) -> Option<PrimitiveType> {
match *self {
QPath { ref self_type, .. } => return self_type.inner_def_id(cache),
Generic(_) | Infer | ImplTrait(_) => return None,
};
- cache.and_then(|c| Primitive(t).def_id_full(c))
+ cache.and_then(|c| Primitive(t).def_id(c))
}
-}
-impl GetDefId for Type {
- fn def_id(&self) -> Option<DefId> {
- self.inner_def_id(None)
+ /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
+ ///
+ /// See [`Self::def_id_no_primitives`] for more.
+ ///
+ /// [clean]: crate::clean
+ crate fn def_id(&self, cache: &Cache) -> Option<DefId> {
+ self.inner_def_id(Some(cache))
}
- fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
- self.inner_def_id(Some(cache))
+ /// Use this method to get the [`DefId`] of a [`clean`] AST node.
+ /// This will return [`None`] when called on a primitive [`clean::Type`].
+ /// Use [`Self::def_id`] if you want to include primitives.
+ ///
+ /// [`clean`]: crate::clean
+ /// [`clean::Type`]: crate::clean::Type
+ // FIXME: get rid of this function and always use `def_id`
+ crate fn def_id_no_primitives(&self) -> Option<DefId> {
+ self.inner_def_id(None)
}
}
crate item_type: Option<Type>,
}
-impl GetDefId for Typedef {
- fn def_id(&self) -> Option<DefId> {
- self.type_.def_id()
- }
-
- fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
- self.type_.def_id_full(cache)
- }
-}
-
#[derive(Clone, Debug)]
crate struct OpaqueTy {
crate bounds: Vec<GenericBound>,
#[derive(Clone, Debug)]
crate struct Impl {
- crate span: Span,
crate unsafety: hir::Unsafety,
crate generics: Generics,
crate trait_: Option<Path>,
crate for_: Type,
crate items: Vec<Item>,
- crate negative_polarity: bool,
- crate synthetic: bool,
- crate blanket_impl: Option<Box<Type>>,
+ crate polarity: ty::ImplPolarity,
+ crate kind: ImplKind,
}
impl Impl {
}
}
+#[derive(Clone, Debug)]
+crate enum ImplKind {
+ Normal,
+ Auto,
+ Blanket(Box<Type>),
+}
+
+impl ImplKind {
+ crate fn is_auto(&self) -> bool {
+ matches!(self, ImplKind::Auto)
+ }
+
+ crate fn is_blanket(&self) -> bool {
+ matches!(self, ImplKind::Blanket(_))
+ }
+
+ crate fn as_blanket_ty(&self) -> Option<&Type> {
+ match self {
+ ImplKind::Blanket(ty) => Some(ty),
+ _ => None,
+ }
+ }
+}
+
#[derive(Clone, Debug)]
crate struct Import {
crate kind: ImportKind,
}
}
}
+
+/// The type, lifetime, or constant that a private type alias's parameter should be
+/// replaced with when expanding a use of that type alias.
+///
+/// For example:
+///
+/// ```
+/// type PrivAlias<T> = Vec<T>;
+///
+/// pub fn public_fn() -> PrivAlias<i32> { vec![] }
+/// ```
+///
+/// `public_fn`'s docs will show it as returning `Vec<i32>`, since `PrivAlias` is private.
+/// [`SubstParam`] is used to record that `T` should be mapped to `i32`.
+crate enum SubstParam {
+ Type(Type),
+ Lifetime(Lifetime),
+ Constant(Constant),
+}
+
+impl SubstParam {
+ crate fn as_ty(&self) -> Option<&Type> {
+ if let Self::Type(ty) = self { Some(ty) } else { None }
+ }
+
+ crate fn as_lt(&self) -> Option<&Lifetime> {
+ if let Self::Lifetime(lt) = self { Some(lt) } else { None }
+ }
+}
let module = crate::visit_ast::RustdocVisitor::new(cx).visit();
let mut externs = Vec::new();
- for &cnum in cx.tcx.crates(()).iter() {
+ for &cnum in cx.tcx.crates(()) {
externs.push(ExternalCrate { crate_num: cnum });
// Analyze doc-reachability for extern items
LibEmbargoVisitor::new(cx).visit_lib(cnum);
}
- externs.sort_unstable_by_key(|e| e.crate_num);
// Clean the crate, translating the entire librustc_ast AST to one that is
// understood by rustdoc.
}
let local_crate = ExternalCrate { crate_num: LOCAL_CRATE };
- let src = local_crate.src(cx.tcx);
- let name = local_crate.name(cx.tcx);
let primitives = local_crate.primitives(cx.tcx);
let keywords = local_crate.keywords(cx.tcx);
{
}
Crate {
- name,
- src,
module,
externs,
primitives,
crate fn qpath_to_string(p: &hir::QPath<'_>) -> String {
let segments = match *p {
- hir::QPath::Resolved(_, ref path) => &path.segments,
- hir::QPath::TypeRelative(_, ref segment) => return segment.ident.to_string(),
+ hir::QPath::Resolved(_, path) => &path.segments,
+ hir::QPath::TypeRelative(_, segment) => return segment.ident.to_string(),
hir::QPath::LangItem(lang_item, ..) => return lang_item.name().to_string(),
};
PatKind::Wild | PatKind::Struct(..) => return kw::Underscore,
PatKind::Binding(_, _, ident, _) => return ident.name,
PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
- PatKind::Or(ref pats) => {
+ PatKind::Or(pats) => {
pats.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(" | ")
}
- PatKind::Tuple(ref elts, _) => format!(
+ PatKind::Tuple(elts, _) => format!(
"({})",
elts.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(", ")
),
- PatKind::Box(ref p) => return name_from_pat(&**p),
- PatKind::Ref(ref p, _) => return name_from_pat(&**p),
+ PatKind::Box(p) => return name_from_pat(&*p),
+ PatKind::Ref(p, _) => return name_from_pat(&*p),
PatKind::Lit(..) => {
warn!(
"tried to get argument name from PatKind::Lit, which is silly in function arguments"
return Symbol::intern("()");
}
PatKind::Range(..) => return kw::Underscore,
- PatKind::Slice(ref begin, ref mid, ref end) => {
+ PatKind::Slice(begin, ref mid, end) => {
let begin = begin.iter().map(|p| name_from_pat(p).to_string());
let mid = mid.as_ref().map(|p| format!("..{}", name_from_pat(&**p))).into_iter();
let end = end.iter().map(|p| name_from_pat(p).to_string());
| Res::NonMacroAttr(_)
| Res::Err => return res.def_id(),
Res::Def(
- TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst | OpaqueTy
- | Field | LifetimeParam | GlobalAsm | Impl | Closure | Generator,
+ TyParam | ConstParam | Ctor(..) | ExternCrate | Use | ForeignMod | AnonConst
+ | InlineConst | OpaqueTy | Field | LifetimeParam | GlobalAsm | Impl | Closure
+ | Generator,
id,
) => return id,
};
/// so that the channel is consistent.
///
/// Set by `bootstrap::Builder::doc_rust_lang_org_channel` in order to keep tests passing on beta/stable.
-crate const DOC_RUST_LANG_ORG_CHANNEL: &'static str = env!("DOC_RUST_LANG_ORG_CHANNEL");
+crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
/// Render a sequence of macro arms in a format suitable for displaying to the user
/// as part of an item declaration.
/// been printed, returns `Err` with the exit code.
crate fn from_matches(matches: &getopts::Matches) -> Result<Options, i32> {
// Check for unstable options.
- nightly_options::check_nightly_options(&matches, &opts());
+ nightly_options::check_nightly_options(matches, &opts());
if matches.opt_present("h") || matches.opt_present("help") {
crate::usage("rustdoc");
return Err(0);
} else if matches.opt_present("version") {
- rustc_driver::version("rustdoc", &matches);
+ rustc_driver::version("rustdoc", matches);
return Err(0);
}
return Err(0);
}
- let color = config::parse_color(&matches);
+ let color = config::parse_color(matches);
let config::JsonConfig { json_rendered, json_unused_externs, .. } =
- config::parse_json(&matches);
- let error_format = config::parse_error_format(&matches, color, json_rendered);
+ config::parse_json(matches);
+ let error_format = config::parse_error_format(matches, color, json_rendered);
let codegen_options = CodegenOptions::build(matches, error_format);
let debugging_opts = DebuggingOptions::build(matches, error_format);
let diag = new_handler(error_format, None, &debugging_opts);
// check for deprecated options
- check_deprecated_options(&matches, &diag);
+ check_deprecated_options(matches, &diag);
let mut emit = Vec::new();
for list in matches.opt_strs("emit") {
.iter()
.map(|s| SearchPath::from_cli_opt(s, error_format))
.collect();
- let externs = parse_externs(&matches, &debugging_opts, error_format);
- let extern_html_root_urls = match parse_extern_html_roots(&matches) {
+ let externs = parse_externs(matches, &debugging_opts, error_format);
+ let extern_html_root_urls = match parse_extern_html_roots(matches) {
Ok(ex) => ex,
Err(err) => {
diag.struct_err(err).emit();
}
}
- let edition = config::parse_crate_edition(&matches);
+ let edition = config::parse_crate_edition(matches);
let mut id_map = html::markdown::IdMap::new();
let external_html = match ExternalHtml::load(
&matches.opt_strs("html-after-content"),
&matches.opt_strs("markdown-before-content"),
&matches.opt_strs("markdown-after-content"),
- nightly_options::match_is_nightly_build(&matches),
+ nightly_options::match_is_nightly_build(matches),
&diag,
&mut id_map,
edition,
/// Used while populating `external_traits` to ensure we don't process the same trait twice at
/// the same time.
crate active_extern_traits: FxHashSet<DefId>,
- // The current set of type and lifetime substitutions,
+ // The current set of parameter substitutions,
// for expanding type aliases at the HIR level:
- /// Table `DefId` of type parameter -> substituted type
- crate ty_substs: FxHashMap<DefId, clean::Type>,
- /// Table `DefId` of lifetime parameter -> substituted lifetime
- crate lt_substs: FxHashMap<DefId, clean::Lifetime>,
- /// Table `DefId` of const parameter -> substituted const
- crate ct_substs: FxHashMap<DefId, clean::Constant>,
+ /// Table `DefId` of type, lifetime, or const parameter -> substituted type, lifetime, or const
+ crate substs: FxHashMap<DefId, clean::SubstParam>,
/// Table synthetic type parameter for `impl Trait` in argument position -> bounds
crate impl_trait_bounds: FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>,
/// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
impl<'tcx> DocContext<'tcx> {
crate fn sess(&self) -> &'tcx Session {
- &self.tcx.sess
+ self.tcx.sess
}
crate fn with_param_env<T, F: FnOnce(&mut Self) -> T>(&mut self, def_id: DefId, f: F) -> T {
/// Call the closure with the given parameters set as
/// the substitutions for a type alias' RHS.
- crate fn enter_alias<F, R>(
- &mut self,
- ty_substs: FxHashMap<DefId, clean::Type>,
- lt_substs: FxHashMap<DefId, clean::Lifetime>,
- ct_substs: FxHashMap<DefId, clean::Constant>,
- f: F,
- ) -> R
+ crate fn enter_alias<F, R>(&mut self, substs: FxHashMap<DefId, clean::SubstParam>, f: F) -> R
where
F: FnOnce(&mut Self) -> R,
{
- let (old_tys, old_lts, old_cts) = (
- mem::replace(&mut self.ty_substs, ty_substs),
- mem::replace(&mut self.lt_substs, lt_substs),
- mem::replace(&mut self.ct_substs, ct_substs),
- );
+ let old_substs = mem::replace(&mut self.substs, substs);
let r = f(self);
- self.ty_substs = old_tys;
- self.lt_substs = old_lts;
- self.ct_substs = old_cts;
+ self.substs = old_substs;
r
}
// Closures' tables come from their outermost function,
// as they are part of the same "inference environment".
// This avoids emitting errors for the parent twice (see similar code in `typeck_with_fallback`)
- let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
- if outer_def_id != def_id {
- return tcx.typeck(outer_def_id);
+ let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()).expect_local();
+ if typeck_root_def_id != def_id {
+ return tcx.typeck(typeck_root_def_id);
}
let hir = tcx.hir();
param_env: ParamEnv::empty(),
external_traits: Default::default(),
active_extern_traits: Default::default(),
- ty_substs: Default::default(),
- lt_substs: Default::default(),
- ct_substs: Default::default(),
+ substs: Default::default(),
impl_trait_bounds: Default::default(),
generated_synthetics: Default::default(),
auto_traits: tcx
_ => continue,
};
for name in value.as_str().split_whitespace() {
- let span = attr.name_value_literal_span().unwrap_or(attr.span());
+ let span = attr.name_value_literal_span().unwrap_or_else(|| attr.span());
manual_passes.extend(parse_pass(name, Some(span)));
}
}
};
if run {
debug!("running pass {}", p.pass.name);
- krate = ctxt.tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt));
+ krate = tcx.sess.time(p.pass.name, || (p.pass.run)(krate, &mut ctxt));
}
}
- ctxt.sess().abort_if_errors();
+ if tcx.sess.diagnostic().has_errors_or_lint_errors() {
+ rustc_errors::FatalError.raise();
+ }
let render_options = ctxt.render_options;
let mut cache = ctxt.cache;
use std::string::ToString;
use std::sync::mpsc::Sender;
-macro_rules! try_err {
- ($e:expr, $file:expr) => {
- match $e {
- Ok(e) => e,
- Err(e) => return Err(E::new(e, $file)),
- }
- };
-}
-
crate trait PathError {
fn new<S, P: AsRef<Path>>(e: S, path: P) -> Self
where
});
});
} else {
- try_err!(fs::write(&path, contents), path);
+ fs::write(&path, contents).map_err(|e| E::new(e, path))?;
}
Ok(())
}
use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{ColorConfig, ErrorReported};
+use rustc_errors::{ColorConfig, ErrorReported, FatalError};
use rustc_hir as hir;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_hir::intravisit;
search_paths: options.libs.clone(),
crate_types,
lint_opts: if !options.display_doctest_warnings { lint_opts } else { vec![] },
- lint_cap: Some(options.lint_cap.unwrap_or_else(|| lint::Forbid)),
+ lint_cap: Some(options.lint_cap.unwrap_or(lint::Forbid)),
cg: options.codegen_options.clone(),
externs: options.externs.clone(),
unstable_features: options.render_options.unstable_features,
collector
});
- compiler.session().abort_if_errors();
+ if compiler.session().diagnostic().has_errors_or_lint_errors() {
+ FatalError.raise();
+ }
let unused_extern_reports = collector.unused_extern_reports.clone();
let compiling_test_count = collector.compiling_test_count.load(Ordering::SeqCst);
.iter()
.map(|uexts| uexts.unused_extern_names.iter().collect::<FxHashSet<&String>>())
.fold(extern_names, |uextsa, uextsb| {
- uextsa.intersection(&uextsb).map(|v| *v).collect::<FxHashSet<&String>>()
+ uextsa.intersection(&uextsb).copied().collect::<FxHashSet<&String>>()
})
.iter()
.map(|v| (*v).clone())
// Add a \n to the end to properly terminate the last line,
// but only if there was output to be printed
- if out_lines.len() > 0 {
+ if !out_lines.is_empty() {
out_lines.push("");
}
let mut attrs = Attributes::from_ast(ast_attrs, None);
if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
- if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
+ if !cfg.matches(&self.sess.parse_sess, Some(self.sess.features_untracked())) {
return;
}
}
StructItem(mut i) => {
let num_fields = i.fields.len();
i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- i.fields_stripped |=
- num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+ if !i.fields_stripped {
+ i.fields_stripped =
+ num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+ }
StructItem(i)
}
UnionItem(mut i) => {
let num_fields = i.fields.len();
i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- i.fields_stripped |=
- num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+ if !i.fields_stripped {
+ i.fields_stripped =
+ num_fields != i.fields.len() || i.fields.iter().any(|f| f.is_stripped());
+ }
UnionItem(i)
}
EnumItem(mut i) => {
let num_variants = i.variants.len();
i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect();
- i.variants_stripped |=
- num_variants != i.variants.len() || i.variants.iter().any(|f| f.is_stripped());
+ if !i.variants_stripped {
+ i.variants_stripped = num_variants != i.variants.len()
+ || i.variants.iter().any(|f| f.is_stripped());
+ }
EnumItem(i)
}
TraitItem(mut i) => {
i.items = i.items.into_iter().filter_map(|x| self.fold_item(x)).collect();
ImplItem(i)
}
- VariantItem(i) => {
- let i2 = i.clone(); // this clone is small
- match i {
- Variant::Struct(mut j) => {
- let num_fields = j.fields.len();
- j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- j.fields_stripped |= num_fields != j.fields.len()
+ VariantItem(i) => match i {
+ Variant::Struct(mut j) => {
+ let num_fields = j.fields.len();
+ j.fields = j.fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+ if !j.fields_stripped {
+ j.fields_stripped = num_fields != j.fields.len()
|| j.fields.iter().any(|f| f.is_stripped());
- VariantItem(Variant::Struct(j))
- }
- Variant::Tuple(fields) => {
- let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
- VariantItem(Variant::Tuple(fields))
}
- _ => VariantItem(i2),
+ VariantItem(Variant::Struct(j))
}
- }
- x => x,
+ Variant::Tuple(fields) => {
+ let fields = fields.into_iter().filter_map(|x| self.fold_item(x)).collect();
+ VariantItem(Variant::Tuple(fields))
+ }
+ Variant::CLike => VariantItem(Variant::CLike),
+ },
+ ExternCrateItem { src: _ }
+ | ImportItem(_)
+ | FunctionItem(_)
+ | TypedefItem(_, _)
+ | OpaqueTyItem(_)
+ | StaticItem(_)
+ | ConstantItem(_)
+ | TraitAliasItem(_)
+ | TyMethodItem(_)
+ | MethodItem(_, _)
+ | StructFieldItem(_)
+ | ForeignFunctionItem(_)
+ | ForeignStaticItem(_)
+ | ForeignTypeItem
+ | MacroItem(_)
+ | ProcMacroItem(_)
+ | PrimitiveItem(_)
+ | AssocConstItem(_, _)
+ | AssocTypeItem(_, _)
+ | KeywordItem(_) => kind,
}
}
fn fold_crate(&mut self, mut c: Crate) -> Crate {
c.module = self.fold_item(c.module).unwrap();
- {
- let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
- for (k, mut v) in external_traits {
- v.trait_.items =
- v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
- c.external_traits.borrow_mut().insert(k, v);
- }
+ let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
+ for (k, mut v) in external_traits {
+ v.trait_.items = v.trait_.items.into_iter().filter_map(|i| self.fold_item(i)).collect();
+ c.external_traits.borrow_mut().insert(k, v);
}
+
c
}
}
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::sym;
-use crate::clean::{self, GetDefId, ItemId, PrimitiveType};
+use crate::clean::{self, ItemId, PrimitiveType};
use crate::config::RenderOptions;
use crate::fold::DocFolder;
use crate::formats::item_type::ItemType;
|| i.trait_
.as_ref()
.map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate))
- || i.for_.def_id().map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
+ || i.for_
+ .def_id(self.cache)
+ .map_or(false, |d| self.cache.masked_crates.contains(&d.krate))
{
return None;
}
// Collect all the implementors of traits.
if let clean::ImplItem(ref i) = *item.kind {
if let Some(trait_) = &i.trait_ {
- if i.blanket_impl.is_none() {
+ if !i.kind.is_blanket() {
self.cache
.implementors
.entry(trait_.def_id())
// inserted later on when serializing the search-index.
if item.def_id.index().map_or(false, |idx| idx != CRATE_DEF_INDEX) {
let desc = item.doc_value().map_or_else(String::new, |x| {
- short_markdown_summary(&x.as_str(), &item.link_names(&self.cache))
+ short_markdown_summary(x.as_str(), &item.link_names(self.cache))
});
self.cache.search_index.push(IndexItem {
ty: item.type_(),
if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) {
for bound in generics {
- if let Some(did) = bound.def_id() {
+ if let Some(did) = bound.def_id(self.cache) {
dids.insert(did);
}
}
let impl_item = Impl { impl_item: item };
if impl_item.trait_did().map_or(true, |d| self.cache.traits.contains_key(&d)) {
for did in dids {
- self.cache.impls.entry(did).or_insert(vec![]).push(impl_item.clone());
+ self.cache.impls.entry(did).or_insert_with(Vec::new).push(impl_item.clone());
}
} else {
let trait_did = impl_item.trait_did().expect("no trait did");
ProcAttribute = 23,
ProcDerive = 24,
TraitAlias = 25,
+ Generic = 26,
}
impl Serialize for ItemType {
| DefKind::Use
| DefKind::ForeignMod
| DefKind::AnonConst
+ | DefKind::InlineConst
| DefKind::OpaqueTy
| DefKind::Field
| DefKind::LifetimeParam
ItemType::ProcAttribute => "attr",
ItemType::ProcDerive => "derive",
ItemType::TraitAlias => "traitalias",
+ ItemType::Generic => "generic",
}
}
}
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_middle::ty;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_target::spec::abi::Abi;
/// Used when rendering a `ResolvedPath` structure. This invokes the `path`
/// rendering function with the necessary arguments for linking to a local path.
-fn resolved_path<'a, 'cx: 'a>(
+fn resolved_path<'cx>(
w: &mut fmt::Formatter<'_>,
did: DefId,
path: &clean::Path,
/// Helper to render type parameters
fn tybounds<'a, 'tcx: 'a>(
- bounds: &'a Vec<clean::PolyTrait>,
+ bounds: &'a [clean::PolyTrait],
lt: &'a Option<clean::Lifetime>,
cx: &'a Context<'tcx>,
) -> impl fmt::Display + 'a + Captures<'tcx> {
if bounds.len() > 1 || trait_lt.is_some() =>
{
write!(f, "{}{}{}(", amp, lt, m)?;
- fmt_type(&ty, f, use_absolute, cx)?;
+ fmt_type(ty, f, use_absolute, cx)?;
write!(f, ")")
}
clean::Generic(..) => {
&format!("{}{}{}", amp, lt, m),
cx,
)?;
- fmt_type(&ty, f, use_absolute, cx)
+ fmt_type(ty, f, use_absolute, cx)
}
_ => {
write!(f, "{}{}{}", amp, lt, m)?;
- fmt_type(&ty, f, use_absolute, cx)
+ fmt_type(ty, f, use_absolute, cx)
}
}
}
}
if let Some(ref ty) = self.trait_ {
- if self.negative_polarity {
- write!(f, "!")?;
+ match self.polarity {
+ ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => {}
+ ty::ImplPolarity::Negative => write!(f, "!")?,
}
fmt::Display::fmt(&ty.print(cx), f)?;
write!(f, " for ")?;
}
- if let Some(ref ty) = self.blanket_impl {
+ if let Some(ref ty) = self.kind.as_blanket_ty() {
fmt_type(ty, f, use_absolute, cx)?;
} else {
fmt_type(&self.for_, f, use_absolute, cx)?;
}
write_header(out, class, extra_content);
- write_code(out, &src, edition, context_info, decoration_info);
+ write_code(out, src, edition, context_info, decoration_info);
write_footer(out, playground_button);
}
impl Decorations {
fn new(info: DecorationInfo) -> Self {
- let (starts, ends) = info
+ // Extract tuples (start, end, kind) into separate sequences of (start, kind) and (end).
+ let (mut starts, mut ends): (Vec<_>, Vec<_>) = info
.0
.into_iter()
.map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
.flatten()
.unzip();
+
+ // Sort the sequences in document order.
+ starts.sort_by_key(|(lo, _)| *lo);
+ ends.sort();
+
Decorations { starts, ends }
}
}
// Assume that '&' or '*' is the reference or dereference operator
// or a reference or pointer type. Unless, of course, it looks like
// a logical and or a multiplication operator: `&&` or `* `.
- TokenKind::Star => match self.peek() {
- Some(TokenKind::Whitespace) => Class::Op,
+ TokenKind::Star => match self.tokens.peek() {
+ Some((TokenKind::Whitespace, _)) => Class::Op,
+ Some((TokenKind::Ident, "mut")) => {
+ self.next();
+ sink(Highlight::Token { text: "*mut", class: Some(Class::RefKeyWord) });
+ return;
+ }
+ Some((TokenKind::Ident, "const")) => {
+ self.next();
+ sink(Highlight::Token { text: "*const", class: Some(Class::RefKeyWord) });
+ return;
+ }
_ => Class::RefKeyWord,
},
- TokenKind::And => match lookahead {
- Some(TokenKind::And) => {
+ TokenKind::And => match self.tokens.peek() {
+ Some((TokenKind::And, _)) => {
self.next();
sink(Highlight::Token { text: "&&", class: Some(Class::Op) });
return;
}
- Some(TokenKind::Eq) => {
+ Some((TokenKind::Eq, _)) => {
self.next();
sink(Highlight::Token { text: "&=", class: Some(Class::Op) });
return;
}
- Some(TokenKind::Whitespace) => Class::Op,
+ Some((TokenKind::Whitespace, _)) => Class::Op,
+ Some((TokenKind::Ident, "mut")) => {
+ self.next();
+ sink(Highlight::Token { text: "&mut", class: Some(Class::RefKeyWord) });
+ return;
+ }
_ => Class::RefKeyWord,
},
.map(|(url, _, _)| url)
}
LinkFromSrc::Primitive(prim) => format::href_with_root_path(
- PrimitiveType::primitive_locations(context.tcx())[&prim],
+ PrimitiveType::primitive_locations(context.tcx())[prim],
context,
Some(context_info.root_path),
)
<span class="attribute">#[<span class="ident">cfg</span>(<span class="ident">target_os</span> <span class="op">=</span> <span class="string">"linux"</span>)]</span>
<span class="kw">fn</span> <span class="ident">main</span>() -> () {
<span class="kw">let</span> <span class="ident">foo</span> <span class="op">=</span> <span class="bool-val">true</span> <span class="op">&&</span> <span class="bool-val">false</span> <span class="op">|</span><span class="op">|</span> <span class="bool-val">true</span>;
- <span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*</span><span class="kw">const</span> () <span class="op">=</span> <span class="number">0</span>;
+ <span class="kw">let</span> <span class="kw">_</span>: <span class="kw-2">*const</span> () <span class="op">=</span> <span class="number">0</span>;
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">&</span><span class="ident">foo</span>;
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="op">&&</span><span class="ident">foo</span>;
<span class="kw">let</span> <span class="kw">_</span> <span class="op">=</span> <span class="kw-2">*</span><span class="ident">foo</span>;
- <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&</span><span class="kw-2">mut</span> <span class="ident">bar</span>);
+ <span class="macro">mac!</span>(<span class="ident">foo</span>, <span class="kw-2">&mut</span> <span class="ident">bar</span>);
<span class="macro">assert!</span>(<span class="self">self</span>.<span class="ident">length</span> <span class="op"><</span> <span class="ident">N</span> <span class="op">&&</span> <span class="ident">index</span> <span class="op"><</span><span class="op">=</span> <span class="self">self</span>.<span class="ident">length</span>);
<span class="ident">::std::env::var</span>(<span class="string">"gateau"</span>).<span class="ident">is_ok</span>();
<span class="attribute">#[<span class="ident">rustfmt::skip</span>]</span>
let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
let style_files = style_files
.iter()
- .filter_map(|t| {
- if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
- })
- .filter_map(|t| if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None })
+ .filter_map(|t| t.path.file_stem().map(|stem| (stem, t.disabled)))
+ .filter_map(|t| t.0.to_str().map(|path| (path, t.1)))
.map(|t| {
format!(
r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
Line::Shown(Cow::Owned(s.replacen("##", "#", 1)))
} else if let Some(stripped) = trimmed.strip_prefix("# ") {
// # text
- Line::Hidden(&stripped)
+ Line::Hidden(stripped)
} else if trimmed == "#" {
// We cannot handle '#text' because it could be #[attr].
Line::Hidden("")
let parse_result = match kind {
CodeBlockKind::Fenced(ref lang) => {
let parse_result =
- LangString::parse_without_check(&lang, self.check_error_codes, false);
+ LangString::parse_without_check(lang, self.check_error_codes, false);
if !parse_result.rust {
return Some(Event::Html(
format!(
loop {
match self.inner.next() {
Some((Event::FootnoteReference(ref reference), range)) => {
- let entry = self.get_entry(&reference);
+ let entry = self.get_entry(reference);
let reference = format!(
"<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{0}</a></sup>",
(*entry).1
string
.split(|c| c == ',' || c == ' ' || c == '\t')
.map(str::trim)
- .map(|token| if token.chars().next() == Some('.') { &token[1..] } else { token })
+ .map(|token| token.strip_prefix('.').unwrap_or(token))
.filter(|token| !token.is_empty())
}
}
x if extra.is_some() => {
let s = x.to_lowercase();
- match if s == "compile-fail" || s == "compile_fail" || s == "compilefail" {
+ if let Some((flag, help)) = if s == "compile-fail"
+ || s == "compile_fail"
+ || s == "compilefail"
+ {
Some((
"compile_fail",
"the code block will either not be tested if not marked as a rust one \
} else {
None
} {
- Some((flag, help)) => {
- if let Some(ref extra) = extra {
- extra.error_invalid_codeblock_attr(
- &format!("unknown attribute `{}`. Did you mean `{}`?", x, flag),
- help,
- );
- }
+ if let Some(extra) = extra {
+ extra.error_invalid_codeblock_attr(
+ &format!("unknown attribute `{}`. Did you mean `{}`?", x, flag),
+ help,
+ );
}
- None => {}
}
seen_other_tags = true;
}
return String::new();
}
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
- }
+ links
+ .iter()
+ .find(|link| &*link.original_text == broken_link.reference)
+ .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
};
let p = Parser::new_with_broken_link_callback(md, main_body_opts(), Some(&mut replacer));
}
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
- }
+ links
+ .iter()
+ .find(|link| &*link.original_text == broken_link.reference)
+ .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
};
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
}
let mut replacer = |broken_link: BrokenLink<'_>| {
- if let Some(link) =
- link_names.iter().find(|link| &*link.original_text == broken_link.reference)
- {
- Some((link.href.as_str().into(), link.new_text.as_str().into()))
- } else {
- None
- }
+ link_names
+ .iter()
+ .find(|link| &*link.original_text == broken_link.reference)
+ .map(|link| (link.href.as_str().into(), link.new_text.as_str().into()))
};
let p = Parser::new_with_broken_link_callback(md, summary_opts(), Some(&mut replacer));
CodeBlockKind::Indented => {
// The ending of the offset goes too far sometime so we reduce it by one in
// these cases.
- if offset.end > offset.start && md.get(offset.end..=offset.end) == Some(&"\n") {
+ if offset.end > offset.start && md.get(offset.end..=offset.end) == Some("\n") {
(
LangString::default(),
offset.start,
+use std::collections::hash_map::Entry;
use std::collections::BTreeMap;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
use serde::ser::{Serialize, SerializeStruct, Serializer};
use crate::clean;
-use crate::clean::types::{
- FnDecl, FnRetTy, GenericBound, Generics, GetDefId, Type, WherePredicate,
-};
+use crate::clean::types::{FnDecl, FnRetTy, GenericBound, Generics, Type, WherePredicate};
use crate::formats::cache::Cache;
use crate::formats::item_type::ItemType;
use crate::html::markdown::short_markdown_summary;
if let Some(&(ref fqp, _)) = cache.paths.get(&did) {
let desc = item
.doc_value()
- .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(&cache)));
+ .map_or_else(String::new, |s| short_markdown_summary(&s, &item.link_names(cache)));
cache.search_index.push(IndexItem {
ty: item.type_(),
name: item.name.unwrap().to_string(),
desc,
parent: Some(did),
parent_idx: None,
- search_type: get_index_search_type(&item, tcx),
+ search_type: get_index_search_type(item, tcx),
aliases: item.attrs.get_doc_aliases(),
});
}
let crate_doc = krate
.module
.doc_value()
- .map_or_else(String::new, |s| short_markdown_summary(&s, &krate.module.link_names(&cache)));
+ .map_or_else(String::new, |s| short_markdown_summary(&s, &krate.module.link_names(cache)));
let Cache { ref mut search_index, ref paths, .. } = *cache;
// Set up alias indexes.
for (i, item) in search_index.iter().enumerate() {
for alias in &item.aliases[..] {
- aliases.entry(alias.to_lowercase()).or_insert(Vec::new()).push(i);
+ aliases.entry(alias.to_lowercase()).or_insert_with(Vec::new).push(i);
}
}
let mut lastpathid = 0usize;
for item in search_index {
- item.parent_idx = item.parent.and_then(|defid| {
- if defid_to_pathid.contains_key(&defid) {
- defid_to_pathid.get(&defid).copied()
- } else {
+ item.parent_idx = item.parent.and_then(|defid| match defid_to_pathid.entry(defid) {
+ Entry::Occupied(entry) => Some(*entry.get()),
+ Entry::Vacant(entry) => {
let pathid = lastpathid;
- defid_to_pathid.insert(defid, pathid);
+ entry.insert(pathid);
lastpathid += 1;
if let Some(&(ref fqp, short)) = paths.get(&defid) {
// Collect the index into a string
format!(
r#""{}":{}"#,
- krate.name,
+ krate.name(tcx),
serde_json::to_string(&CrateData {
doc: crate_doc,
items: crate_items,
item: &clean::Item,
tcx: TyCtxt<'tcx>,
) -> Option<IndexItemFunctionType> {
- let (all_types, ret_types) = match *item.kind {
+ let (mut inputs, mut output) = match *item.kind {
clean::FunctionItem(ref f) => get_all_types(&f.generics, &f.decl, tcx),
clean::MethodItem(ref m, _) => get_all_types(&m.generics, &m.decl, tcx),
clean::TyMethodItem(ref m) => get_all_types(&m.generics, &m.decl, tcx),
_ => return None,
};
- let inputs = all_types
- .iter()
- .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
- .filter(|a| a.ty.name.is_some())
- .collect();
- let output = ret_types
- .iter()
- .map(|(ty, kind)| TypeWithKind::from((get_index_type(&ty), *kind)))
- .filter(|a| a.ty.name.is_some())
- .collect::<Vec<_>>();
+ inputs.retain(|a| a.ty.name.is_some());
+ output.retain(|a| a.ty.name.is_some());
let output = if output.is_empty() { None } else { Some(output) };
Some(IndexItemFunctionType { inputs, output })
}
-fn get_index_type(clean_type: &clean::Type) -> RenderType {
+fn get_index_type(clean_type: &clean::Type, generics: Vec<TypeWithKind>) -> RenderType {
RenderType {
name: get_index_type_name(clean_type, true).map(|s| s.as_str().to_ascii_lowercase()),
- generics: get_generics(clean_type),
+ generics: if generics.is_empty() { None } else { Some(generics) },
}
}
}
}
-/// Return a list of generic parameters for use in the search index.
-///
-/// This function replaces bounds with types, so that `T where T: Debug` just becomes `Debug`.
-/// It does return duplicates, and that's intentional, since search queries like `Result<usize, usize>`
-/// are supposed to match only results where both parameters are `usize`.
-fn get_generics(clean_type: &clean::Type) -> Option<Vec<String>> {
- clean_type.generics().and_then(|types| {
- let r = types
- .iter()
- .filter_map(|t| {
- get_index_type_name(t, false).map(|name| name.as_str().to_ascii_lowercase())
- })
- .collect::<Vec<_>>();
- if r.is_empty() { None } else { Some(r) }
- })
-}
-
/// The point of this function is to replace bounds with types.
///
/// i.e. `[T, U]` when you have the following bounds: `T: Display, U: Option<T>` will return
generics: &Generics,
arg: &Type,
tcx: TyCtxt<'tcx>,
- recurse: i32,
- res: &mut FxHashSet<(Type, ItemType)>,
-) -> usize {
- fn insert(res: &mut FxHashSet<(Type, ItemType)>, tcx: TyCtxt<'_>, ty: Type) -> usize {
- if let Some(kind) = ty.def_id().map(|did| tcx.def_kind(did).into()) {
- res.insert((ty, kind));
- 1
+ recurse: usize,
+ res: &mut Vec<TypeWithKind>,
+) {
+ fn insert_ty(
+ res: &mut Vec<TypeWithKind>,
+ tcx: TyCtxt<'_>,
+ ty: Type,
+ mut generics: Vec<TypeWithKind>,
+ ) {
+ let is_full_generic = ty.is_full_generic();
+
+ if is_full_generic && generics.len() == 1 {
+ // In this case, no need to go through an intermediate state if the generics
+ // contains only one element.
+ //
+ // For example:
+ //
+ // fn foo<T: Display>(r: Option<T>) {}
+ //
+ // In this case, it would contain:
+ //
+ // ```
+ // [{
+ // name: "option",
+ // generics: [{
+ // name: "",
+ // generics: [
+ // name: "Display",
+ // generics: []
+ // }]
+ // }]
+ // }]
+ // ```
+ //
+ // After removing the intermediate (unnecessary) full generic, it'll become:
+ //
+ // ```
+ // [{
+ // name: "option",
+ // generics: [{
+ // name: "Display",
+ // generics: []
+ // }]
+ // }]
+ // ```
+ //
+ // To be noted that it can work if there is ONLY ONE generic, otherwise we still
+ // need to keep it as is!
+ res.push(generics.pop().unwrap());
+ return;
+ }
+ let mut index_ty = get_index_type(&ty, generics);
+ if index_ty.name.as_ref().map(|s| s.is_empty()).unwrap_or(true) {
+ return;
+ }
+ if is_full_generic {
+ // We remove the name of the full generic because we have no use for it.
+ index_ty.name = Some(String::new());
+ res.push(TypeWithKind::from((index_ty, ItemType::Generic)));
+ } else if let Some(kind) = ty.def_id_no_primitives().map(|did| tcx.def_kind(did).into()) {
+ res.push(TypeWithKind::from((index_ty, kind)));
} else if ty.is_primitive() {
// This is a primitive, let's store it as such.
- res.insert((ty, ItemType::Primitive));
- 1
- } else {
- 0
+ res.push(TypeWithKind::from((index_ty, ItemType::Primitive)));
}
}
if recurse >= 10 {
// FIXME: remove this whole recurse thing when the recursion bug is fixed
- return 0;
+ return;
}
- let mut nb_added = 0;
- if let &Type::Generic(arg_s) = arg {
+ if let Type::Generic(arg_s) = *arg {
if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
- WherePredicate::BoundPredicate { ty, .. } => ty.def_id() == arg.def_id(),
+ WherePredicate::BoundPredicate { ty, .. } => {
+ ty.def_id_no_primitives() == arg.def_id_no_primitives()
+ }
_ => false,
}) {
+ let mut ty_generics = Vec::new();
let bounds = where_pred.get_bounds().unwrap_or_else(|| &[]);
for bound in bounds.iter() {
if let GenericBound::TraitBound(poly_trait, _) = bound {
continue;
}
if let Some(ty) = x.get_type() {
- let adds = get_real_types(generics, &ty, tcx, recurse + 1, res);
- nb_added += adds;
- if adds == 0 && !ty.is_full_generic() {
- nb_added += insert(res, tcx, ty);
- }
+ get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics);
}
}
}
}
+ insert_ty(res, tcx, arg.clone(), ty_generics);
}
if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
+ let mut ty_generics = Vec::new();
for bound in bound.get_bounds().unwrap_or(&[]) {
if let Some(path) = bound.get_trait_path() {
let ty = Type::ResolvedPath { did: path.def_id(), path };
- let adds = get_real_types(generics, &ty, tcx, recurse + 1, res);
- nb_added += adds;
- if adds == 0 && !ty.is_full_generic() {
- nb_added += insert(res, tcx, ty);
- }
+ get_real_types(generics, &ty, tcx, recurse + 1, &mut ty_generics);
}
}
+ insert_ty(res, tcx, arg.clone(), ty_generics);
}
} else {
- nb_added += insert(res, tcx, arg.clone());
- if let Some(gens) = arg.generics() {
- for gen in gens.iter() {
- if gen.is_full_generic() {
- nb_added += get_real_types(generics, gen, tcx, recurse + 1, res);
- } else {
- nb_added += insert(res, tcx, (*gen).clone());
- }
+ let mut ty_generics = Vec::new();
+ if let Some(arg_generics) = arg.generics() {
+ for gen in arg_generics.iter() {
+ get_real_types(generics, gen, tcx, recurse + 1, &mut ty_generics);
}
}
+ insert_ty(res, tcx, arg.clone(), ty_generics);
}
- nb_added
}
/// Return the full list of types when bounds have been resolved.
generics: &Generics,
decl: &FnDecl,
tcx: TyCtxt<'tcx>,
-) -> (Vec<(Type, ItemType)>, Vec<(Type, ItemType)>) {
- let mut all_types = FxHashSet::default();
+) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
+ let mut all_types = Vec::new();
for arg in decl.inputs.values.iter() {
if arg.type_.is_self_type() {
continue;
}
- let mut args = FxHashSet::default();
+ // FIXME: performance wise, it'd be much better to move `args` declaration outside of the
+ // loop and replace this line with `args.clear()`.
+ let mut args = Vec::new();
get_real_types(generics, &arg.type_, tcx, 0, &mut args);
if !args.is_empty() {
+ // FIXME: once back to performance improvements, replace this line with:
+ // `all_types.extend(args.drain(..));`.
all_types.extend(args);
} else {
- if let Some(kind) = arg.type_.def_id().map(|did| tcx.def_kind(did).into()) {
- all_types.insert((arg.type_.clone(), kind));
+ if let Some(kind) = arg.type_.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
+ {
+ all_types.push(TypeWithKind::from((get_index_type(&arg.type_, vec![]), kind)));
}
}
}
- let ret_types = match decl.output {
+ let mut ret_types = Vec::new();
+ match decl.output {
FnRetTy::Return(ref return_type) => {
- let mut ret = FxHashSet::default();
- get_real_types(generics, &return_type, tcx, 0, &mut ret);
- if ret.is_empty() {
- if let Some(kind) = return_type.def_id().map(|did| tcx.def_kind(did).into()) {
- ret.insert((return_type.clone(), kind));
+ get_real_types(generics, return_type, tcx, 0, &mut ret_types);
+ if ret_types.is_empty() {
+ if let Some(kind) =
+ return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
+ {
+ ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind)));
}
}
- ret.into_iter().collect()
}
- _ => Vec::new(),
+ _ => {}
};
- (all_types.into_iter().collect(), ret_types)
+ (all_types, ret_types)
}
use std::sync::mpsc::{channel, Receiver};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_hir::def_id::LOCAL_CRATE;
+use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::edition::Edition;
BASIC_KEYWORDS,
};
-use crate::clean;
-use crate::clean::ExternalCrate;
+use crate::clean::{self, ExternalCrate};
use crate::config::RenderOptions;
use crate::docfs::{DocFS, PathError};
use crate::error::Error;
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
use crate::html::{layout, sources};
use crate::scrape_examples::AllCallLocations;
+use crate::try_err;
/// Major driving force in all rustdoc rendering. This contains information
/// about where in the tree-like hierarchy rendering is occurring and controls
/// real location of an item. This is used to allow external links to
/// publicly reused items to redirect to the right location.
pub(super) render_redirect_pages: bool,
+ /// Tracks section IDs for `Deref` targets so they match in both the main
+ /// body and the sidebar.
+ pub(super) deref_id_map: RefCell<FxHashMap<DefId, String>>,
/// The map used to ensure all generated 'id=' attributes are unique.
pub(super) id_map: RefCell<IdMap>,
/// Shared mutable state.
// `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Context<'_>, 104);
+rustc_data_structures::static_assert_size!(Context<'_>, 144);
/// Shared mutable state used in [`Context`] and elsewhere.
crate struct SharedContext<'tcx> {
}
pub(super) fn sess(&self) -> &'tcx Session {
- &self.shared.tcx.sess
+ self.shared.tcx.sess
}
pub(super) fn derive_id(&self, id: String) -> String {
};
title.push_str(" - Rust");
let tyname = it.type_();
- let desc = it.doc_value().as_ref().map(|doc| plain_text_summary(&doc));
+ let desc = it.doc_value().as_ref().map(|doc| plain_text_summary(doc));
let desc = if let Some(desc) = desc {
desc
} else if it.is_crate() {
..
} = options;
- let src_root = match krate.src {
+ let src_root = match krate.src(tcx) {
FileName::Real(ref p) => match p.local_path_if_available().parent() {
Some(p) => p.to_path_buf(),
None => PathBuf::new(),
let mut playground = None;
if let Some(url) = playground_url {
playground =
- Some(markdown::Playground { crate_name: Some(krate.name.to_string()), url });
+ Some(markdown::Playground { crate_name: Some(krate.name(tcx).to_string()), url });
}
let mut layout = layout::Layout {
logo: String::new(),
favicon: String::new(),
external_html,
default_settings,
- krate: krate.name.to_string(),
+ krate: krate.name(tcx).to_string(),
css_file_extension: extension_css,
generate_search_filter,
scrape_examples_extension: !call_locations.is_empty(),
}
(sym::html_playground_url, Some(s)) => {
playground = Some(markdown::Playground {
- crate_name: Some(krate.name.to_string()),
+ crate_name: Some(krate.name(tcx).to_string()),
url: s.to_string(),
});
}
}
}
- let (mut krate, local_sources, matches) = collect_spans_and_sources(
+ let (local_sources, matches) = collect_spans_and_sources(
tcx,
- krate,
+ &krate,
&src_root,
include_sources,
generate_link_to_definition,
dst,
render_redirect_pages: false,
id_map: RefCell::new(id_map),
+ deref_id_map: RefCell::new(FxHashMap::default()),
shared: Rc::new(scx),
include_sources,
};
if emit_crate {
- krate = sources::render(&mut cx, krate)?;
+ sources::render(&mut cx, &krate)?;
}
// Build our search index
current: self.current.clone(),
dst: self.dst.clone(),
render_redirect_pages: self.render_redirect_pages,
+ deref_id_map: RefCell::new(FxHashMap::default()),
id_map: RefCell::new(IdMap::new()),
shared: Rc::clone(&self.shared),
include_sources: self.include_sources,
mod templates;
mod write_shared;
-crate use context::*;
-crate use span_map::{collect_spans_and_sources, LinkFromSrc};
+crate use self::context::*;
+crate use self::span_map::{collect_spans_and_sources, LinkFromSrc};
use std::collections::VecDeque;
use std::default::Default;
use rustc_hir::def_id::DefId;
use rustc_hir::Mutability;
use rustc_middle::middle::stability;
+use rustc_middle::ty;
use rustc_middle::ty::TyCtxt;
use rustc_span::{
symbol::{kw, sym, Symbol},
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
-use crate::clean::{self, GetDefId, ItemId, RenderedLink, SelfTy};
+use crate::clean::{self, ItemId, RenderedLink, SelfTy};
use crate::docfs::PathError;
use crate::error::Error;
use crate::formats::cache::Cache;
use crate::html::highlight;
use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
use crate::html::sources;
-use crate::scrape_examples::CallData;
+use crate::scrape_examples::{CallData, CallLocation};
+use crate::try_none;
/// A pair of name and its optional document.
crate type NameDoc = (String, Option<String>);
#[derive(Debug)]
crate struct RenderType {
name: Option<String>,
- generics: Option<Vec<String>>,
+ generics: Option<Vec<TypeWithKind>>,
}
/// Full type of functions/methods in the search index.
// If we couldn't figure out a type, just write `null`.
let mut iter = self.inputs.iter();
if match self.output {
- Some(ref output) => iter.chain(output.iter()).any(|ref i| i.ty.name.is_none()),
- None => iter.any(|ref i| i.ty.name.is_none()),
+ Some(ref output) => iter.chain(output.iter()).any(|i| i.ty.name.is_none()),
+ None => iter.any(|i| i.ty.name.is_none()),
} {
serializer.serialize_none()
} else {
AssocItemLink::GotoSource(did, provided_methods) => {
// We're creating a link from an impl-item to the corresponding
// trait-item and need to map the anchored type accordingly.
- let ty = if provided_methods.contains(&name) {
+ let ty = if provided_methods.contains(name) {
ItemType::Method
} else {
ItemType::TyMethod
name = name,
generics = g.print(cx),
decl = d.full_print(header_len, indent, header.asyncness, cx),
- notable_traits = notable_traits_decl(&d, cx),
+ notable_traits = notable_traits_decl(d, cx),
where_clause = print_where_clause(g, cx, indent, end_newline),
)
}
.iter()
.filter_map(|attr| {
if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
- Some(pprust::attribute_to_string(&attr).replace("\n", "").replace(" ", " "))
+ Some(pprust::attribute_to_string(attr).replace("\n", "").replace(" ", " "))
} else {
None
}
impl<'a> AssocItemLink<'a> {
fn anchor(&self, id: &'a str) -> Self {
match *self {
- AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(&id)),
+ AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(id)),
ref other => *other,
}
}
containing_item: &clean::Item,
it: DefId,
what: AssocItemRender<'_>,
+) {
+ let mut derefs = FxHashSet::default();
+ derefs.insert(it);
+ render_assoc_items_inner(w, cx, containing_item, it, what, &mut derefs)
+}
+
+fn render_assoc_items_inner(
+ w: &mut Buffer,
+ cx: &Context<'_>,
+ containing_item: &clean::Item,
+ it: DefId,
+ what: AssocItemRender<'_>,
+ derefs: &mut FxHashSet<DefId>,
) {
info!("Documenting associated items of {:?}", containing_item.name);
let cache = cx.cache();
};
let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
if !non_trait.is_empty() {
+ let mut tmp_buf = Buffer::empty_from(w);
let render_mode = match what {
AssocItemRender::All => {
- w.write_str(
+ tmp_buf.write_str(
"<h2 id=\"implementations\" class=\"small-section-header\">\
Implementations<a href=\"#implementations\" class=\"anchor\"></a>\
</h2>",
RenderMode::Normal
}
AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
+ let id =
+ cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
+ if let Some(def_id) = type_.def_id(cx.cache()) {
+ cx.deref_id_map.borrow_mut().insert(def_id, id.clone());
+ }
write!(
- w,
- "<h2 id=\"deref-methods\" class=\"small-section-header\">\
+ tmp_buf,
+ "<h2 id=\"{id}\" class=\"small-section-header\">\
<span>Methods from {trait_}<Target = {type_}></span>\
- <a href=\"#deref-methods\" class=\"anchor\"></a>\
+ <a href=\"#{id}\" class=\"anchor\"></a>\
</h2>",
+ id = id,
trait_ = trait_.print(cx),
type_ = type_.print(cx),
);
RenderMode::ForDeref { mut_: deref_mut_ }
}
};
+ let mut impls_buf = Buffer::empty_from(w);
for i in &non_trait {
render_impl(
- w,
+ &mut impls_buf,
cx,
i,
containing_item,
},
);
}
+ if !impls_buf.is_empty() {
+ w.push_buffer(tmp_buf);
+ w.push_buffer(impls_buf);
+ }
}
- if let AssocItemRender::DerefFor { .. } = what {
- return;
- }
+
if !traits.is_empty() {
let deref_impl =
traits.iter().find(|t| t.trait_did() == cx.tcx().lang_items().deref_trait());
if let Some(impl_) = deref_impl {
let has_deref_mut =
traits.iter().any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
- render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
+ render_deref_methods(w, cx, impl_, containing_item, has_deref_mut, derefs);
+ }
+
+ // If we were already one level into rendering deref methods, we don't want to render
+ // anything after recursing into any further deref methods above.
+ if let AssocItemRender::DerefFor { .. } = what {
+ return;
}
+
let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
- traits.iter().partition(|t| t.inner_impl().synthetic);
+ traits.iter().partition(|t| t.inner_impl().kind.is_auto());
let (blanket_impl, concrete): (Vec<&&Impl>, _) =
- concrete.into_iter().partition(|t| t.inner_impl().blanket_impl.is_some());
+ concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
- let mut impls = Buffer::empty_from(&w);
+ let mut impls = Buffer::empty_from(w);
render_impls(cx, &mut impls, &concrete, containing_item);
let impls = impls.into_inner();
if !impls.is_empty() {
impl_: &Impl,
container_item: &clean::Item,
deref_mut: bool,
+ derefs: &mut FxHashSet<DefId>,
) {
let cache = cx.cache();
let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target);
let what =
AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
- if let Some(did) = target.def_id_full(cache) {
- if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cache) {
+ if let Some(did) = target.def_id(cache) {
+ if let Some(type_did) = impl_.inner_impl().for_.def_id(cache) {
// `impl Deref<Target = S> for S`
- if did == type_did {
+ if did == type_did || !derefs.insert(did) {
// Avoid infinite cycles
return;
}
}
- render_assoc_items(w, cx, container_item, did, what);
+ render_assoc_items_inner(w, cx, container_item, did, what, derefs);
} else {
if let Some(prim) = target.primitive_type() {
if let Some(&did) = cache.primitive_locations.get(&prim) {
- render_assoc_items(w, cx, container_item, did, what);
+ render_assoc_items_inner(w, cx, container_item, did, what, derefs);
}
}
}
fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
let mut out = Buffer::html();
- if let Some(did) = decl.output.def_id_full(cx.cache()) {
+ if let Some(did) = decl.output.as_return().and_then(|t| t.def_id(cx.cache())) {
if let Some(impls) = cx.cache().impls.get(&did) {
for i in impls {
let impl_ = i.inner_impl();
&& match render_mode {
RenderMode::Normal => true,
RenderMode::ForDeref { mut_: deref_mut_ } => {
- should_render_item(&item, deref_mut_, cx.tcx())
+ should_render_item(item, deref_mut_, cx.tcx())
}
};
&mut impl_items,
cx,
&t.trait_,
- &i.inner_impl(),
+ i.inner_impl(),
&i.impl_item,
parent,
render_mode,
error_codes: cx.shared.codes,
edition: cx.shared.edition(),
playground: &cx.shared.playground,
- heading_offset: HeadingOffset::H2
+ heading_offset: HeadingOffset::H4
}
.into_string()
);
if let Some(impl_) =
v.iter().find(|i| i.trait_did() == cx.tcx().lang_items().deref_trait())
{
- sidebar_deref_methods(cx, out, impl_, v);
+ let mut derefs = FxHashSet::default();
+ derefs.insert(did);
+ sidebar_deref_methods(cx, out, impl_, v, &mut derefs);
}
let format_impls = |impls: Vec<&Impl>| {
let i_display = format!("{:#}", i.print(cx));
let out = Escape(&i_display);
let encoded = small_url_encode(format!("{:#}", i.print(cx)));
- let generated = format!(
- "<a href=\"#impl-{}\">{}{}</a>",
- encoded,
- if it.inner_impl().negative_polarity { "!" } else { "" },
- out
- );
+ let prefix = match it.inner_impl().polarity {
+ ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
+ ty::ImplPolarity::Negative => "!",
+ };
+ let generated =
+ format!("<a href=\"#impl-{}\">{}{}</a>", encoded, prefix, out);
if links.insert(generated.clone()) { Some(generated) } else { None }
} else {
None
};
let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
- v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().synthetic);
- let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = concrete
- .into_iter()
- .partition::<Vec<_>, _>(|i| i.inner_impl().blanket_impl.is_some());
+ v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto());
+ let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
+ concrete.into_iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_blanket());
let concrete_format = format_impls(concrete);
let synthetic_format = format_impls(synthetic);
}
}
-fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec<Impl>) {
+fn sidebar_deref_methods(
+ cx: &Context<'_>,
+ out: &mut Buffer,
+ impl_: &Impl,
+ v: &[Impl],
+ derefs: &mut FxHashSet<DefId>,
+) {
let c = cx.cache();
debug!("found Deref: {:?}", impl_);
})
{
debug!("found target, real_target: {:?} {:?}", target, real_target);
- if let Some(did) = target.def_id_full(c) {
- if let Some(type_did) = impl_.inner_impl().for_.def_id_full(c) {
+ if let Some(did) = target.def_id(c) {
+ if let Some(type_did) = impl_.inner_impl().for_.def_id(c) {
// `impl Deref<Target = S> for S`
- if did == type_did {
+ if did == type_did || !derefs.insert(did) {
// Avoid infinite cycles
return;
}
}
let deref_mut = v.iter().any(|i| i.trait_did() == cx.tcx().lang_items().deref_mut_trait());
let inner_impl = target
- .def_id_full(c)
+ .def_id(c)
.or_else(|| {
target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned())
})
})
.collect::<Vec<_>>();
if !ret.is_empty() {
+ let map;
+ let id = if let Some(target_def_id) = real_target.def_id(c) {
+ map = cx.deref_id_map.borrow();
+ map.get(&target_def_id).expect("Deref section without derived id")
+ } else {
+ "deref-methods"
+ };
write!(
out,
- "<h3 class=\"sidebar-title\"><a href=\"#deref-methods\">Methods from {}<Target={}></a></h3>",
+ "<h3 class=\"sidebar-title\"><a href=\"#{}\">Methods from {}<Target={}></a></h3>",
+ id,
Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
Escape(&format!("{:#}", real_target.print(cx))),
);
out.push_str("</div>");
}
}
+
+ // Recurse into any further impls that might exist for `target`
+ if let Some(target_did) = target.def_id_no_primitives() {
+ if let Some(target_impls) = c.impls.get(&target_did) {
+ if let Some(target_deref_impl) = target_impls.iter().find(|i| {
+ i.inner_impl()
+ .trait_
+ .as_ref()
+ .map(|t| Some(t.def_id()) == cx.tcx().lang_items().deref_trait())
+ .unwrap_or(false)
+ }) {
+ sidebar_deref_methods(cx, out, target_deref_impl, target_impls, derefs);
+ }
+ }
+ }
}
}
fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
match *item.kind {
clean::ItemKind::ImplItem(ref i) => {
- if let Some(ref trait_) = i.trait_ {
+ i.trait_.as_ref().map(|trait_| {
// Alternative format produces no URLs,
// so this parameter does nothing.
- Some((
+ (
format!("{:#}", i.for_.print(cx)),
get_id_for_impl_on_foreign_type(&i.for_, trait_, cx),
- ))
- } else {
- None
- }
+ )
+ })
}
_ => None,
}
let mut res = implementors
.iter()
.filter(|i| {
- i.inner_impl()
- .for_
- .def_id_full(cache)
- .map_or(false, |d| !cache.paths.contains_key(&d))
+ i.inner_impl().for_.def_id(cache).map_or(false, |d| !cache.paths.contains_key(&d))
})
.filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
.collect::<Vec<_>>();
let mut variants = e
.variants
.iter()
- .filter_map(|v| match v.name {
- Some(ref name) => Some(format!("<a href=\"#variant.{name}\">{name}</a>", name = name)),
- _ => None,
+ .filter_map(|v| {
+ v.name
+ .as_ref()
+ .map(|name| format!("<a href=\"#variant.{name}\">{name}</a>", name = name))
})
.collect::<Vec<_>>();
if !variants.is_empty() {
ItemType::ProcAttribute => ("attributes", "Attribute Macros"),
ItemType::ProcDerive => ("derives", "Derive Macros"),
ItemType::TraitAlias => ("trait-aliases", "Trait aliases"),
+ ItemType::Generic => unreachable!(),
}
}
id = id
);
+ // Create a URL to a particular location in a reverse-dependency's source file
+ let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) {
+ let (line_lo, line_hi) = loc.call_expr.line_span;
+ let (anchor, title) = if line_lo == line_hi {
+ ((line_lo + 1).to_string(), format!("line {}", line_lo + 1))
+ } else {
+ (
+ format!("{}-{}", line_lo + 1, line_hi + 1),
+ format!("lines {}-{}", line_lo + 1, line_hi + 1),
+ )
+ };
+ let url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
+ (url, title)
+ };
+
// Generate the HTML for a single example, being the title and code block
let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| -> bool {
let contents = match fs::read_to_string(&path) {
let (line_lo, line_hi) = loc.call_expr.line_span;
let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
let line_range = (line_lo - line_min, line_hi - line_min);
- let (anchor, line_title) = if line_lo == line_hi {
- (format!("{}", line_lo + 1), format!("line {}", line_lo + 1))
- } else {
- (
- format!("{}-{}", line_lo + 1, line_hi + 1),
- format!("lines {}-{}", line_lo + 1, line_hi + 1),
- )
- };
- let line_url = format!("{}{}#{}", cx.root_path(), call_data.url, anchor);
+ let (line_url, line_title) = link_to_loc(call_data, loc);
(byte_range, (line_range, line_url, line_title))
})
if it.peek().is_some() {
write!(w, r#"<div class="example-links">Additional examples can be found in:<br><ul>"#);
it.for_each(|(_, call_data)| {
+ let (url, _) = link_to_loc(&call_data, &call_data.locations[0]);
write!(
w,
- r#"<li><a href="{root}{url}">{name}</a></li>"#,
- root = cx.root_path(),
- url = call_data.url,
+ r#"<li><a href="{url}">{name}</a></li>"#,
+ url = url,
name = call_data.display_name
);
});
render_impl, render_stability_since_raw, write_srclink, AssocItemLink, Context,
ImplRenderingParameters,
};
-use crate::clean::{self, GetDefId};
+use crate::clean;
use crate::formats::item_type::ItemType;
use crate::formats::{AssocItemRender, Impl, RenderMode};
use crate::html::escape::Escape;
use serde::Serialize;
-const ITEM_TABLE_OPEN: &'static str = "<div class=\"item-table\">";
-const ITEM_TABLE_CLOSE: &'static str = "</div>";
-const ITEM_TABLE_ROW_OPEN: &'static str = "<div class=\"item-row\">";
-const ITEM_TABLE_ROW_CLOSE: &'static str = "</div>";
+const ITEM_TABLE_OPEN: &str = "<div class=\"item-table\">";
+const ITEM_TABLE_CLOSE: &str = "</div>";
+const ITEM_TABLE_ROW_OPEN: &str = "<div class=\"item-row\">";
+const ITEM_TABLE_ROW_CLOSE: &str = "</div>";
// A component in a `use` path, like `string` in std::string::ToString
#[derive(Serialize)]
}
let (local, foreign) = implementors.iter().partition::<Vec<_>, _>(|i| {
- i.inner_impl().for_.def_id_full(cache).map_or(true, |d| cache.paths.contains_key(&d))
+ i.inner_impl().for_.def_id(cache).map_or(true, |d| cache.paths.contains_key(&d))
});
let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
- local.iter().partition(|i| i.inner_impl().synthetic);
+ local.iter().partition(|i| i.inner_impl().kind.is_auto());
synthetic.sort_by(|a, b| compare_impl(a, b, cx));
concrete.sort_by(|a, b| compare_impl(a, b, cx));
render_impl(
w,
cx,
- &implementor,
+ implementor,
it,
assoc_link,
RenderMode::Normal,
if let Some(stability_class) = field.stability_class(cx.tcx()) {
write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
}
- document(w, cx, field, Some(it), HeadingOffset::H2);
+ document(w, cx, field, Some(it), HeadingOffset::H3);
}
}
let def_id = it.def_id.expect_def_id();
w.write_str("</code>");
render_stability_since(w, variant, it, cx.tcx());
w.write_str("</div>");
- document(w, cx, variant, Some(it), HeadingOffset::H2);
+ document(w, cx, variant, Some(it), HeadingOffset::H3);
document_non_exhaustive(w, variant);
use crate::clean::Variant;
f = field.name.as_ref().unwrap(),
t = ty.print(cx)
);
- document(w, cx, field, Some(variant), HeadingOffset::H2);
+ document(w, cx, field, Some(variant), HeadingOffset::H4);
}
_ => unreachable!(),
}
name = field_name,
ty = ty.print(cx)
);
- document(w, cx, field, Some(it), HeadingOffset::H2);
+ document(w, cx, field, Some(it), HeadingOffset::H3);
}
}
}
);
if let Some(g) = g {
write!(w, "{}", g.print(cx));
- write!(w, "{}", print_where_clause(&g, cx, 0, true));
+ write!(w, "{}", print_where_clause(g, cx, 0, true));
}
write!(w, " {{\n{}", tab);
/// only keep the `lo` and `hi`.
crate fn collect_spans_and_sources(
tcx: TyCtxt<'_>,
- krate: clean::Crate,
+ krate: &clean::Crate,
src_root: &Path,
include_sources: bool,
generate_link_to_definition: bool,
-) -> (clean::Crate, FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
+) -> (FxHashMap<PathBuf, String>, FxHashMap<Span, LinkFromSrc>) {
let mut visitor = SpanMapVisitor { tcx, matches: FxHashMap::default() };
if include_sources {
if generate_link_to_definition {
tcx.hir().walk_toplevel_module(&mut visitor);
}
- let (krate, sources) = sources::collect_local_sources(tcx, src_root, krate);
- (krate, sources, visitor.matches)
+ let sources = sources::collect_local_sources(tcx, src_root, &krate);
+ (sources, visitor.matches)
} else {
- (krate, Default::default(), Default::default())
+ (Default::default(), Default::default())
}
}
}
for bound in p.bounds {
if let Some(trait_ref) = bound.trait_ref() {
- self.handle_path(&trait_ref.path, None);
+ self.handle_path(trait_ref.path, None);
}
}
}
if !span.overlaps(m.inner) {
// Now that we confirmed it's a file import, we want to get the span for the module
// name only and not all the "mod foo;".
- if let Some(node) = self.tcx.hir().find(id) {
- match node {
- Node::Item(item) => {
- self.matches
- .insert(item.ident.span, LinkFromSrc::Local(clean::Span::new(m.inner)));
- }
- _ => {}
- }
+ if let Some(Node::Item(item)) = self.tcx.hir().find(id) {
+ self.matches.insert(item.ident.span, LinkFromSrc::Local(clean::Span::new(m.inner)));
}
}
intravisit::walk_mod(self, m, id);
}
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
- match expr.kind {
- ExprKind::MethodCall(segment, method_span, _, _) => {
- if let Some(hir_id) = segment.hir_id {
- let hir = self.tcx.hir();
- let body_id = hir.enclosing_body_owner(hir_id);
- let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| {
- self.tcx.typeck_body(
- hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
- )
- });
- if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
- self.matches.insert(
- method_span,
- match hir.span_if_local(def_id) {
- Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
- None => LinkFromSrc::External(def_id),
- },
- );
- }
+ if let ExprKind::MethodCall(segment, method_span, _, _) = expr.kind {
+ if let Some(hir_id) = segment.hir_id {
+ let hir = self.tcx.hir();
+ let body_id = hir.enclosing_body_owner(hir_id);
+ let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| {
+ self.tcx.typeck_body(
+ hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
+ )
+ });
+ if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
+ self.matches.insert(
+ method_span,
+ match hir.span_if_local(def_id) {
+ Some(span) => LinkFromSrc::Local(clean::Span::new(span)),
+ None => LinkFromSrc::External(def_id),
+ },
+ );
}
}
- _ => {}
}
intravisit::walk_expr(self, expr);
}
use crate::docfs::PathError;
use crate::error::Error;
use crate::html::{layout, static_files};
+use crate::{try_err, try_none};
static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
map! {
"SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD,
"SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC,
"SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE,
- "noto-sans-kr-regular.woff2" => static_files::noto_sans_kr::REGULAR2,
- "noto-sans-kr-regular.woff" => static_files::noto_sans_kr::REGULAR,
- "noto-sans-kr-LICENSE.txt" => static_files::noto_sans_kr::LICENSE,
+ "NanumBarunGothic.ttf.woff2" => static_files::nanum_barun_gothic::REGULAR2,
+ "NanumBarunGothic.ttf.woff" => static_files::nanum_barun_gothic::REGULAR,
+ "NanumBarunGothic-LICENSE.txt" => static_files::nanum_barun_gothic::LICENSE,
"LICENSE-MIT.txt" => static_files::LICENSE_MIT,
"LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
"COPYRIGHT.txt" => static_files::COPYRIGHT,
) -> Result<(), Error> {
if minify {
let contents = contents.as_ref();
- let contents = if resource.extension() == Some(&OsStr::new("css")) {
+ let contents = if resource.extension() == Some(OsStr::new("css")) {
minifier::css::minify(contents).map_err(|e| {
Error::new(format!("failed to minify CSS file: {}", e), resource.path(self))
})?
let dst = cx.dst.join(&format!("source-files{}.js", cx.shared.resource_suffix));
let make_sources = || {
let (mut all_sources, _krates) =
- try_err!(collect(&dst, &krate.name.as_str(), "sourcesIndex"), &dst);
+ try_err!(collect(&dst, &krate.name(cx.tcx()).as_str(), "sourcesIndex"), &dst);
all_sources.push(format!(
"sourcesIndex[\"{}\"] = {};",
- &krate.name,
+ &krate.name(cx.tcx()),
hierarchy.to_json_string()
));
all_sources.sort();
// Update the search index and crate list.
let dst = cx.dst.join(&format!("search-index{}.js", cx.shared.resource_suffix));
- let (mut all_indexes, mut krates) = try_err!(collect_json(&dst, &krate.name.as_str()), &dst);
+ let (mut all_indexes, mut krates) =
+ try_err!(collect_json(&dst, &krate.name(cx.tcx()).as_str()), &dst);
all_indexes.push(search_index);
- krates.push(krate.name.to_string());
+ krates.push(krate.name(cx.tcx()).to_string());
krates.sort();
// Sort the indexes by crate so the file will be generated identically even
} else {
Some(Implementor {
text: imp.inner_impl().print(false, cx).to_string(),
- synthetic: imp.inner_impl().synthetic,
+ synthetic: imp.inner_impl().kind.is_auto(),
types: collect_paths_for_type(imp.inner_impl().for_.clone(), cache),
})
}
let implementors = format!(
r#"implementors["{}"] = {};"#,
- krate.name,
+ krate.name(cx.tcx()),
serde_json::to_string(&implementors).unwrap()
);
mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1]));
let (mut all_implementors, _) =
- try_err!(collect(&mydst, &krate.name.as_str(), "implementors"), &mydst);
+ try_err!(collect(&mydst, &krate.name(cx.tcx()).as_str(), "implementors"), &mydst);
all_implementors.push(implementors);
// Sort the implementors by crate so the file will be generated
// identically even with rustdoc running in parallel.
use crate::clean;
use crate::docfs::PathError;
use crate::error::Error;
-use crate::fold::DocFolder;
use crate::html::format::Buffer;
use crate::html::highlight;
use crate::html::layout;
use crate::html::render::{Context, BASIC_KEYWORDS};
+use crate::visit::DocVisitor;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::ty::TyCtxt;
use std::fs;
use std::path::{Component, Path, PathBuf};
-crate fn render(cx: &mut Context<'_>, krate: clean::Crate) -> Result<clean::Crate, Error> {
+crate fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> {
info!("emitting source files");
- let dst = cx.dst.join("src").join(&*krate.name.as_str());
+
+ let dst = cx.dst.join("src").join(&*krate.name(cx.tcx()).as_str());
cx.shared.ensure_dir(&dst)?;
- let mut folder = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() };
- Ok(folder.fold_crate(krate))
+
+ let mut collector = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() };
+ collector.visit_crate(krate);
+ Ok(())
}
crate fn collect_local_sources<'tcx>(
tcx: TyCtxt<'tcx>,
src_root: &Path,
- krate: clean::Crate,
-) -> (clean::Crate, FxHashMap<PathBuf, String>) {
+ krate: &clean::Crate,
+) -> FxHashMap<PathBuf, String> {
let mut lsc = LocalSourcesCollector { tcx, local_sources: FxHashMap::default(), src_root };
-
- let krate = lsc.fold_crate(krate);
- (krate, lsc.local_sources)
+ lsc.visit_crate(krate);
+ lsc.local_sources
}
struct LocalSourcesCollector<'a, 'tcx> {
}
fn is_real_and_local(span: clean::Span, sess: &Session) -> bool {
- span.filename(sess).is_real() && span.cnum(sess) == LOCAL_CRATE
+ span.cnum(sess) == LOCAL_CRATE && span.filename(sess).is_real()
}
impl LocalSourcesCollector<'_, '_> {
return;
}
let filename = span.filename(sess);
- let p = match filename {
- FileName::Real(ref file) => match file.local_path() {
- Some(p) => p.to_path_buf(),
- _ => return,
- },
- _ => return,
+ let p = if let FileName::Real(file) = filename {
+ match file.into_local_path() {
+ Some(p) => p,
+ None => return,
+ }
+ } else {
+ return;
};
if self.local_sources.contains_key(&*p) {
// We've already emitted this source
}
let mut href = String::new();
- clean_path(&self.src_root, &p, false, |component| {
+ clean_path(self.src_root, &p, false, |component| {
href.push_str(&component.to_string_lossy());
href.push('/');
});
}
}
-impl DocFolder for LocalSourcesCollector<'_, '_> {
- fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
- self.add_local_source(&item);
+impl DocVisitor for LocalSourcesCollector<'_, '_> {
+ fn visit_item(&mut self, item: &clean::Item) {
+ self.add_local_source(item);
- // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value,
- // we could return None here without having to walk the rest of the crate.
- Some(self.fold_item_recur(item))
+ self.visit_item_recur(item)
}
}
emitted_local_sources: FxHashSet<PathBuf>,
}
-impl DocFolder for SourceCollector<'_, '_> {
- fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+impl DocVisitor for SourceCollector<'_, '_> {
+ fn visit_item(&mut self, item: &clean::Item) {
+ if !self.cx.include_sources {
+ return;
+ }
+
let tcx = self.cx.tcx();
let span = item.span(tcx);
let sess = tcx.sess;
// If we're not rendering sources, there's nothing to do.
// If we're including source files, and we haven't seen this file yet,
// then we need to render it out to the filesystem.
- if self.cx.include_sources && is_real_and_local(span, sess) {
+ if is_real_and_local(span, sess) {
let filename = span.filename(sess);
let span = span.inner();
let pos = sess.source_map().lookup_source_file(span.lo());
}
};
}
- // FIXME: if `include_sources` isn't set and DocFolder didn't require consuming the crate by value,
- // we could return None here without having to walk the rest of the crate.
- Some(self.fold_item_recur(item))
+
+ self.visit_item_recur(item)
}
}
};
// Remove the utf-8 BOM if any
- let contents = if contents.starts_with('\u{feff}') { &contents[3..] } else { &contents };
+ let contents = contents.strip_prefix('\u{feff}').unwrap_or(&contents);
// Create the intermediate directories
let mut cur = self.dst.clone();
contents,
self.cx.shared.edition(),
file_span,
- &self.cx,
+ self.cx,
&root_path,
None,
SourceContext::Standalone,
/* It requires JS to work so no need to display it in this case. */
display: none;
}
+
+.sub {
+ /* The search bar and related controls don't work without JS */
+ display: none;
+}
+
+#theme-picker {
+ display: none;
+}
/* Avoid using legacy CJK serif fonts in Windows like Batang. */
@font-face {
- font-family: 'Noto Sans KR';
- src: url("noto-sans-kr-regular.woff2") format("woff2"),
- url("noto-sans-kr-regular.woff") format("woff");
+ font-family: 'NanumBarunGothic';
+ src: url("NanumBarunGothic.ttf.woff2") format("woff2"),
+ url("NanumBarunGothic.ttf.woff") format("woff");
font-display: swap;
- unicode-range: U+AC00-D7AF, U+3130-318F, U+1100-11FF, U+A960-A97F, U+D7B0-D7FF;
+ unicode-range: U+AC00-D7AF, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF;
}
* {
/* General structure and fonts */
body {
- font: 16px/1.4 "Source Serif 4", "Noto Sans KR", serif;
+ font: 16px/1.4 "Source Serif 4", NanumBarunGothic, serif;
margin: 0;
position: relative;
padding: 10px 15px 20px 15px;
margin: 20px 0 15px 0;
padding-bottom: 6px;
}
-h5, h6 {
+.docblock h3, .docblock h4, h5, h6 {
margin: 15px 0 5px 0;
}
h1.fqn {
h1.fqn > .in-band > a:hover {
text-decoration: underline;
}
-h2, h3, h4 {
+/* The only headings that get underlines are:
+ Markdown-generated headings within the top-doc
+ Rustdoc-generated h2 section headings (e.g. "Implementations", "Required Methods", etc)
+ Underlines elsewhere in the documentation break up visual flow and tend to invert
+ section hierarchies. */
+h2,
+.top-doc h3,
+.top-doc h4,
+.sidebar .others h3 {
border-bottom: 1px solid;
}
h3.code-header {
.content ul.crate a.crate, a.srclink,
/* This selector is for the items listed in the "all items" page. */
#main > ul.docblock > li > a {
- font-family: "Fira Sans", Arial, sans-serif;
+ font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
}
.content ul.crate a.crate {
position: relative;
}
-.docblock > * {
+.docblock > :not(.information) {
max-width: 100%;
overflow-x: auto;
}
box-shadow: 0 0 0 1px #148099,0 0 0 2px transparent;
}
-.search-input:disabled {
- background-color: #3e3e3e;
-}
-
.module-item .stab,
.import-item .stab {
color: #000;
border-color: #008dfd;
}
-.search-input:disabled {
- background-color: #c5c4c4;
-}
-
#crate-search + .search-input:focus {
box-shadow: 0 0 8px 4px #078dd8;
}
border-color: #66afe9;
}
-.search-input:disabled {
- background-color: #e6e6e6;
-}
-
#crate-search + .search-input:focus {
box-shadow: 0 0 8px #078dd8;
}
--- /dev/null
+Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/),
+
+with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic,
+NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen,
+Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco,
+NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic,
+Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+++ /dev/null
-Copyright 2014, 2015 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-
-This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
search_input.placeholder = searchState.input.origPlaceholder;
});
- search_input.removeAttribute('disabled');
+ if (search_input.value != '') {
+ loadSearch();
+ }
// `crates{version}.js` should always be loaded before this script, so we can use it
// safely.
// delayed sidebar rendering.
window.initSidebarItems = function(items) {
var sidebar = document.getElementsByClassName("sidebar-elems")[0];
+ var others;
var current = window.sidebarCurrent;
function addSidebarCrates(crates) {
li.appendChild(link);
ul.appendChild(li);
}
- sidebar.appendChild(div);
+ others.appendChild(div);
}
function block(shortty, longty) {
ul.appendChild(li);
}
div.appendChild(ul);
- sidebar.appendChild(div);
+ others.appendChild(div);
}
if (sidebar) {
+ others = document.createElement("div");
+ others.className = "others";
+ sidebar.appendChild(others);
+
var isModule = hasClass(document.body, "mod");
if (!isModule) {
block("primitive", "Primitive Types");
var elems = Object.create(null);
var elength = obj[GENERICS_DATA].length;
for (var x = 0; x < elength; ++x) {
- if (!elems[obj[GENERICS_DATA][x]]) {
- elems[obj[GENERICS_DATA][x]] = 0;
+ if (!elems[obj[GENERICS_DATA][x][NAME]]) {
+ elems[obj[GENERICS_DATA][x][NAME]] = 0;
}
- elems[obj[GENERICS_DATA][x]] += 1;
+ elems[obj[GENERICS_DATA][x][NAME]] += 1;
}
var total = 0;
var done = 0;
// Check for type name and type generics (if any).
function checkType(obj, val, literalSearch) {
var lev_distance = MAX_LEV_DISTANCE + 1;
+ var tmp_lev = MAX_LEV_DISTANCE + 1;
var len, x, firstGeneric;
if (obj[NAME] === val.name) {
if (literalSearch) {
var elems = Object.create(null);
len = obj[GENERICS_DATA].length;
for (x = 0; x < len; ++x) {
- if (!elems[obj[GENERICS_DATA][x]]) {
- elems[obj[GENERICS_DATA][x]] = 0;
+ if (!elems[obj[GENERICS_DATA][x][NAME]]) {
+ elems[obj[GENERICS_DATA][x][NAME]] = 0;
}
- elems[obj[GENERICS_DATA][x]] += 1;
+ elems[obj[GENERICS_DATA][x][NAME]] += 1;
}
var allFound = true;
// If the type has generics but don't match, then it won't return at this point.
// Otherwise, `checkGenerics` will return 0 and it'll return.
if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length !== 0) {
- var tmp_lev = checkGenerics(obj, val);
+ tmp_lev = checkGenerics(obj, val);
if (tmp_lev <= MAX_LEV_DISTANCE) {
return tmp_lev;
}
if ((!val.generics || val.generics.length === 0) &&
obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
return obj[GENERICS_DATA].some(
- function(name) {
- return name === val.name;
+ function(gen) {
+ return gen[NAME] === val.name;
});
}
return false;
// a levenshtein distance value that isn't *this* good so it goes
// into the search results but not too high.
lev_distance = Math.ceil((checkGenerics(obj, val) + lev_distance) / 2);
- } else if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
+ }
+ if (obj.length > GENERICS_DATA && obj[GENERICS_DATA].length > 0) {
// We can check if the type we're looking for is inside the generics!
var olength = obj[GENERICS_DATA].length;
for (x = 0; x < olength; ++x) {
- lev_distance = Math.min(levenshtein(obj[GENERICS_DATA][x], val.name),
- lev_distance);
+ tmp_lev = Math.min(levenshtein(obj[GENERICS_DATA][x][NAME], val.name), tmp_lev);
+ }
+ if (tmp_lev !== 0) {
+ // If we didn't find a good enough result, we go check inside the generics of
+ // the generics.
+ for (x = 0; x < olength && tmp_lev !== 0; ++x) {
+ tmp_lev = Math.min(
+ checkType(obj[GENERICS_DATA][x], val, literalSearch),
+ tmp_lev
+ );
+ }
}
}
// Now whatever happens, the returned distance is "less good" so we should mark it
// as such, and so we add 1 to the distance to make it "less good".
- return lev_distance + 1;
+ return Math.min(lev_distance, tmp_lev) + 1;
}
function findArg(obj, val, literalSearch, typeFilter) {
crate static LICENSE: &[u8] = include_bytes!("static/fonts/SourceCodePro-LICENSE.txt");
}
-crate mod noto_sans_kr {
- /// The file `noto-sans-kr.woff`, the Regular variant of the Noto Sans KR font.
- crate static REGULAR: &[u8] = include_bytes!("static/fonts/noto-sans-kr-regular.woff");
-
- /// The file `noto-sans-kr.woff2`, the Regular variant of the Noto Sans KR font.
- crate static REGULAR2: &[u8] = include_bytes!("static/fonts/noto-sans-kr-regular.woff2");
-
- /// The file `noto-sans-kr-LICENSE.txt`, the license text of the Noto Sans KR font.
- crate static LICENSE: &[u8] = include_bytes!("static/fonts/noto-sans-kr-LICENSE.txt");
+/// Files related to the Nanum Barun Gothic font.
+///
+/// These files are used to avoid some legacy CJK serif fonts in Windows.
+///
+/// Note that the Noto Sans KR font, which was used previously but was not very readable on Windows,
+/// has been replaced by the Nanum Barun Gothic font. This is due to Windows' implementation of font
+/// rendering that distorts OpenType fonts too much.
+///
+/// The font files were generated with these commands:
+///
+/// ```sh
+/// pyftsubset NanumBarunGothic.ttf \
+/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
+/// --output-file=NanumBarunGothic.ttf.woff --flavor=woff
+/// ```
+/// ```sh
+/// pyftsubset NanumBarunGothic.ttf \
+/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
+/// --output-file=NanumBarunGothic.ttf.woff2 --flavor=woff2
+/// ```
+crate mod nanum_barun_gothic {
+ /// The file `NanumBarunGothic.ttf.woff`, the Regular variant of the Nanum Barun Gothic font.
+ crate static REGULAR: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff");
+
+ /// The file `NanumBarunGothic.ttf.woff2`, the Regular variant of the Nanum Barun Gothic font.
+ crate static REGULAR2: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff2");
+
+ /// The file `NanumBarunGothic-LICENSE.txt`, the license text of the Nanum Barun Gothic font.
+ crate static LICENSE: &[u8] = include_bytes!("static/fonts/NanumBarunGothic-LICENSE.txt");
}
/// Files related to the sidebar in rustdoc sources.
<input {# -#}
class="search-input" {# -#}
name="search" {# -#}
- disabled {# -#}
autocomplete="off" {# -#}
spellcheck="false" {# -#}
placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
data-search-js="{{static_root_path | safe}}search{{page.resource_suffix}}.js"> {#- -#}
</div>
<script src="{{static_root_path | safe}}main{{page.resource_suffix}}.js"></script> {#- -#}
- {%- if layout.scrape_examples_extension -%}
- <script src="{{static_root_path | safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
- {%- endif -%}
{%- for script in page.static_extra_scripts -%}
<script src="{{static_root_path | safe}}{{script}}.js"></script> {#- -#}
{% endfor %}
+ {%- if layout.scrape_examples_extension -%}
+ <script src="{{page.root_path | safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
+ {%- endif -%}
{%- for script in page.extra_scripts -%}
<script src="{{page.root_path | safe}}{{script}}.js"></script> {#- -#}
{% endfor %}
use rustc_ast::ast;
use rustc_hir::{def::CtorKind, def_id::DefId};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::CRATE_DEF_INDEX;
use rustc_span::Pos;
.map(|t| {
clean::GenericBound::TraitBound(t, rustc_hir::TraitBoundModifier::None)
})
- .chain(lt.into_iter().map(|lt| clean::GenericBound::Outlives(lt)))
+ .chain(lt.map(clean::GenericBound::Outlives))
.map(|bound| bound.into_tcx(tcx))
.collect(),
}
impl FromWithTcx<clean::Impl> for Impl {
fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
let provided_trait_methods = impl_.provided_trait_methods(tcx);
- let clean::Impl {
- unsafety,
- generics,
- trait_,
- for_,
- items,
- negative_polarity,
- synthetic,
- blanket_impl,
- span: _span,
- } = impl_;
+ let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
// FIXME: should `trait_` be a clean::Path equivalent in JSON?
let trait_ = trait_.map(|path| {
let did = path.def_id();
clean::ResolvedPath { path, did }.into_tcx(tcx)
});
+ // FIXME: use something like ImplKind in JSON?
+ let (synthetic, blanket_impl) = match kind {
+ clean::ImplKind::Normal => (false, None),
+ clean::ImplKind::Auto => (true, None),
+ clean::ImplKind::Blanket(ty) => (false, Some(*ty)),
+ };
+ let negative_polarity = match polarity {
+ ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => false,
+ ty::ImplPolarity::Negative => true,
+ };
Impl {
is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
generics: generics.into_tcx(tcx),
items: ids(items),
negative: negative_polarity,
synthetic,
- blanket_impl: blanket_impl.map(|x| (*x).into_tcx(tcx)),
+ blanket_impl: blanket_impl.map(|x| x.into_tcx(tcx)),
}
}
}
TraitAlias => ItemKind::TraitAlias,
ProcAttribute => ItemKind::ProcAttribute,
ProcDerive => ItemKind::ProcDerive,
+ Generic => unreachable!(),
}
}
}
#![feature(control_flow_enum)]
#![feature(box_syntax)]
#![feature(in_band_lifetimes)]
+#![feature(let_else)]
#![feature(nll)]
#![feature(test)]
#![feature(crate_visibility_modifier)]
}}
}
-#[macro_use]
-mod externalfiles;
-
mod clean;
mod config;
mod core;
mod docfs;
+mod doctest;
mod doctree;
-#[macro_use]
mod error;
-mod doctest;
+mod externalfiles;
mod fold;
mod formats;
// used by the error-index generator, so it needs to be public
mod passes;
mod scrape_examples;
mod theme;
+mod visit;
mod visit_ast;
mod visit_lib;
// We need to hold on to the complete resolver, so we cause everything to be
// cloned for the analysis passes to use. Suboptimal, but necessary in the
// current architecture.
- let resolver = core::create_resolver(queries, &sess);
+ let resolver = core::create_resolver(queries, sess);
- if sess.has_errors() {
+ if sess.diagnostic().has_errors_or_lint_errors() {
sess.fatal("Compilation failed, aborting rustdoc");
}
use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
-use crate::fold::DocFolder;
use crate::html::markdown::main_body_opts;
+use crate::visit::DocVisitor;
use core::ops::Range;
use pulldown_cmark::{Event, Parser, Tag};
use regex::Regex;
) {
trace!("looking for raw urls in {}", text);
// For now, we only check "full" URLs (meaning, starting with "http://" or "https://").
- for match_ in URL_REGEX.find_iter(&text) {
+ for match_ in URL_REGEX.find_iter(text) {
let url = match_.as_str();
let url_range = match_.range();
f(
}
crate fn check_bare_urls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
- BareUrlsLinter { cx }.fold_crate(krate)
+ BareUrlsLinter { cx }.visit_crate(&krate);
+ krate
}
-impl<'a, 'tcx> DocFolder for BareUrlsLinter<'a, 'tcx> {
- fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for BareUrlsLinter<'a, 'tcx> {
+ fn visit_item(&mut self, item: &Item) {
let hir_id = match DocContext::as_local_hir_id(self.cx.tcx, item.def_id) {
Some(hir_id) => hir_id,
None => {
// If non-local, no need to check anything.
- return Some(self.fold_item_recur(item));
+ return;
}
};
let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
}
}
- Some(self.fold_item_recur(item))
+ self.visit_item_recur(item)
}
}
use crate::clean;
use crate::core::DocContext;
-use crate::fold::{self, DocFolder};
use crate::html::markdown::{find_testable_code, ErrorCodes};
use crate::passes::check_doc_test_visibility::{should_have_doc_example, Tests};
use crate::passes::Pass;
+use crate::visit::DocVisitor;
use rustc_hir as hir;
use rustc_lint::builtin::MISSING_DOCS;
use rustc_middle::lint::LintLevelSource;
fn calculate_doc_coverage(krate: clean::Crate, ctx: &mut DocContext<'_>) -> clean::Crate {
let mut calc = CoverageCalculator { items: Default::default(), ctx };
- let krate = calc.fold_crate(krate);
+ calc.visit_crate(&krate);
calc.print_results();
}
}
-impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> {
- fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> {
+impl<'a, 'b> DocVisitor for CoverageCalculator<'a, 'b> {
+ fn visit_item(&mut self, i: &clean::Item) {
+ if !i.def_id.is_local() {
+ // non-local items are skipped because they can be out of the users control,
+ // especially in the case of trait impls, which rustdoc eagerly inlines
+ return;
+ }
+
match *i.kind {
- _ if !i.def_id.is_local() => {
- // non-local items are skipped because they can be out of the users control,
- // especially in the case of trait impls, which rustdoc eagerly inlines
- return Some(i);
- }
clean::StrippedItem(..) => {
// don't count items in stripped modules
- return Some(i);
+ return;
}
// docs on `use` and `extern crate` statements are not displayed, so they're not
// worth counting
}
}
- Some(self.fold_item_recur(i))
+ self.visit_item_recur(i)
}
}
use crate::clean;
use crate::core::DocContext;
-use crate::fold::DocFolder;
use crate::html::markdown::{self, RustCodeBlock};
use crate::passes::Pass;
+use crate::visit::DocVisitor;
crate const CHECK_CODE_BLOCK_SYNTAX: Pass = Pass {
name: "check-code-block-syntax",
};
crate fn check_code_block_syntax(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
- SyntaxChecker { cx }.fold_crate(krate)
+ SyntaxChecker { cx }.visit_crate(&krate);
+ krate
}
struct SyntaxChecker<'a, 'tcx> {
let source = dox[code_block.code].to_owned();
let sess = ParseSess::with_span_handler(handler, sm);
- let edition = code_block.lang_string.edition.unwrap_or(self.cx.tcx.sess.edition());
+ let edition = code_block.lang_string.edition.unwrap_or_else(|| self.cx.tcx.sess.edition());
let expn_data = ExpnData::default(
ExpnKind::AstPass(AstPass::TestHarness),
DUMMY_SP,
// The span and whether it is precise or not.
let (sp, precise_span) = match super::source_span_for_markdown_range(
self.cx.tcx,
- &dox,
+ dox,
&code_block.range,
&item.attrs,
) {
// FIXME(#67563): Provide more context for these errors by displaying the spans inline.
for message in buffer.messages.iter() {
- diag.note(&message);
+ diag.note(message);
}
diag.emit();
}
}
-impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> {
- fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
+impl<'a, 'tcx> DocVisitor for SyntaxChecker<'a, 'tcx> {
+ fn visit_item(&mut self, item: &clean::Item) {
if let Some(dox) = &item.attrs.collapsed_doc_value() {
let sp = item.attr_span(self.cx.tcx);
let extra = crate::html::markdown::ExtraInfo::new_did(
item.def_id.expect_def_id(),
sp,
);
- for code_block in markdown::rust_code_blocks(&dox, &extra) {
- self.check_rust_syntax(&item, &dox, code_block);
+ for code_block in markdown::rust_code_blocks(dox, &extra) {
+ self.check_rust_syntax(&item, dox, code_block);
}
}
- Some(self.fold_item_recur(item))
+ self.visit_item_recur(item)
}
}
use crate::clean;
use crate::clean::*;
use crate::core::DocContext;
-use crate::fold::DocFolder;
use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString};
+use crate::visit::DocVisitor;
use crate::visit_ast::inherits_doc_hidden;
use rustc_hir as hir;
use rustc_middle::lint::LintLevelSource;
crate fn check_doc_test_visibility(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
let mut coll = DocTestVisibilityLinter { cx };
-
- coll.fold_crate(krate)
+ coll.visit_crate(&krate);
+ krate
}
-impl<'a, 'tcx> DocFolder for DocTestVisibilityLinter<'a, 'tcx> {
- fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for DocTestVisibilityLinter<'a, 'tcx> {
+ fn visit_item(&mut self, item: &Item) {
let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);
look_for_tests(self.cx, &dox, &item);
- Some(self.fold_item_recur(item))
+ self.visit_item_recur(item)
}
}
let mut tests = Tests { found_tests: 0 };
- find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);
+ find_testable_code(dox, &mut tests, ErrorCodes::No, false, None);
if tests.found_tests == 0 && cx.tcx.sess.is_nightly_build() {
- if should_have_doc_example(cx, &item) {
+ if should_have_doc_example(cx, item) {
debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
let sp = item.attr_span(cx.tcx);
cx.tcx.struct_span_lint_hir(
use crate::clean::{self, utils::find_nearest_parent_module, Crate, Item, ItemLink, PrimitiveType};
use crate::core::DocContext;
-use crate::fold::DocFolder;
use crate::html::markdown::{markdown_links, MarkdownLink};
use crate::lint::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS};
use crate::passes::Pass;
+use crate::visit::DocVisitor;
mod early;
crate use early::load_intra_link_crates;
};
fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
- LinkCollector {
+ let mut collector = LinkCollector {
cx,
mod_ids: Vec::new(),
kind_side_channel: Cell::new(None),
visited_links: FxHashMap::default(),
- }
- .fold_crate(krate)
+ };
+ collector.visit_crate(&krate);
+ krate
}
/// Top-level errors emitted by this pass.
) -> Result<(Res, Option<String>), ErrorKind<'path>> {
let tcx = self.cx.tcx;
let no_res = || ResolutionFailure::NotResolved {
- module_id: module_id,
+ module_id,
partial_res: None,
unresolved: path_str.into(),
};
fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> {
let result = self.cx.enter_resolver(|resolver| {
resolver
- .resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id)
+ .resolve_str_path_error(DUMMY_SP, path_str, ns, module_id)
.and_then(|(_, res)| res.try_into())
});
debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
ty::Uint(uty) => Res::Primitive(uty.into()),
ty::Float(fty) => Res::Primitive(fty.into()),
ty::Str => Res::Primitive(Str),
- ty::Tuple(ref tys) if tys.is_empty() => Res::Primitive(Unit),
+ ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit),
ty::Tuple(_) => Res::Primitive(Tuple),
ty::Array(..) => Res::Primitive(Array),
ty::Slice(_) => Res::Primitive(Slice),
)
}
-impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> {
- fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
+ fn visit_item(&mut self, item: &Item) {
use rustc_middle::ty::DefIdTree;
let parent_node =
}
}
- Some(if item.is_mod() {
+ if item.is_mod() {
if !inner_docs {
self.mod_ids.push(item.def_id.expect_def_id());
}
- let ret = self.fold_item_recur(item);
+ self.visit_item_recur(item);
self.mod_ids.pop();
- ret
} else {
- self.fold_item_recur(item)
- })
+ self.visit_item_recur(item)
+ }
}
}
}
// Parse and strip the disambiguator from the link, if present.
- let (disambiguator, path_str, link_text) = match Disambiguator::from_str(&link) {
+ let (disambiguator, path_str, link_text) = match Disambiguator::from_str(link) {
Ok(Some((d, path, link_text))) => (Some(d), path.trim(), link_text.trim()),
Ok(None) => (None, link.trim(), link.trim()),
Err((err_msg, relative_range)) => {
// Only report error if we would not have ignored this link. See issue #83859.
if !should_ignore_link_with_disambiguators(link) {
- let no_backticks_range = range_between_backticks(&ori_link);
+ let no_backticks_range = range_between_backticks(ori_link);
let disambiguator_range = (no_backticks_range.start + relative_range.start)
..(no_backticks_range.start + relative_range.end);
return Some(Err(PreprocessingError::Disambiguator(disambiguator_range, err_msg)));
// Strip generics from the path.
let path_str = if path_str.contains(['<', '>'].as_slice()) {
- match strip_generics_from_path(&path_str) {
+ match strip_generics_from_path(path_str) {
Ok(path) => path,
Err(err_kind) => {
debug!("link has malformed generics: {}", path_str);
if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
&& !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
{
- privacy_error(self.cx, &diag_info, &path_str);
+ privacy_error(self.cx, &diag_info, path_str);
}
}
let span =
super::source_span_for_markdown_range(tcx, dox, link_range, &item.attrs).map(|sp| {
- if dox.bytes().nth(link_range.start) == Some(b'`')
- && dox.bytes().nth(link_range.end - 1) == Some(b'`')
+ if dox.as_bytes().get(link_range.start) == Some(&b'`')
+ && dox.as_bytes().get(link_range.end - 1) == Some(&b'`')
{
sp.with_lo(sp.lo() + BytePos(1)).with_hi(sp.hi() - BytePos(1))
} else {
};
name = start;
for ns in [TypeNS, ValueNS, MacroNS] {
- if let Some(res) =
- collector.check_full_res(ns, &start, module_id, &None)
+ if let Some(res) = collector.check_full_res(ns, start, module_id, &None)
{
debug!("found partial_res={:?}", res);
*partial_res = Some(res);
| Use
| LifetimeParam
| Ctor(_, _)
- | AnonConst => {
+ | AnonConst
+ | InlineConst => {
let note = assoc_item_not_allowed(res);
if let Some(span) = sp {
diag.span_label(span, ¬e);
let attrs = crate::clean::Attributes::from_ast(attrs, None);
for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() {
debug!(?doc);
- for link in markdown_links(&doc.as_str()) {
+ for link in markdown_links(doc.as_str()) {
debug!(?link.link);
let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
x.path_str
span,
&path_str,
TypeNS,
- parent_module.unwrap_or(self.current_mod.to_def_id()),
+ parent_module.unwrap_or_else(|| self.current_mod.to_def_id()),
);
});
}
use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
-use crate::fold::DocFolder;
+use crate::visit::DocVisitor;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_hir::def_id::DefId;
use rustc_middle::ty::DefIdTree;
use rustc_span::symbol::sym;
description: "retrieves trait impls for items in the crate",
};
-crate fn collect_trait_impls(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
- let (mut krate, synth_impls) = cx.sess().time("collect_synthetic_impls", || {
+crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate {
+ let synth_impls = cx.sess().time("collect_synthetic_impls", || {
let mut synth = SyntheticImplCollector { cx, impls: Vec::new() };
- (synth.fold_crate(krate), synth.impls)
+ synth.visit_crate(&krate);
+ synth.impls
});
let prims: FxHashSet<PrimitiveType> = krate.primitives.iter().map(|p| p.1).collect();
let crate_items = {
let mut coll = ItemCollector::new();
- krate = cx.sess().time("collect_items_for_trait_impls", || coll.fold_crate(krate));
+ cx.sess().time("collect_items_for_trait_impls", || coll.visit_crate(&krate));
coll.items
};
for &cnum in cx.tcx.crates(()).iter() {
for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() {
- cx.tcx.sess.prof.generic_activity("build_extern_trait_impl").run(|| {
- inline::build_impl(cx, None, did, None, &mut new_items);
- });
+ inline::build_impl(cx, None, did, None, &mut new_items);
}
}
}
let mut cleaner = BadImplStripper { prims, items: crate_items };
+ let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
+
+ // Follow all `Deref` targets of included items and recursively add them as valid
+ fn add_deref_target(
+ map: &FxHashMap<DefId, &Type>,
+ cleaner: &mut BadImplStripper,
+ type_did: DefId,
+ ) {
+ if let Some(target) = map.get(&type_did) {
+ debug!("add_deref_target: type {:?}, target {:?}", type_did, target);
+ if let Some(target_prim) = target.primitive_type() {
+ cleaner.prims.insert(target_prim);
+ } else if let Some(target_did) = target.def_id_no_primitives() {
+ // `impl Deref<Target = S> for S`
+ if target_did == type_did {
+ // Avoid infinite cycles
+ return;
+ }
+ cleaner.items.insert(target_did.into());
+ add_deref_target(map, cleaner, target_did);
+ }
+ }
+ }
// scan through included items ahead of time to splice in Deref targets to the "valid" sets
for it in &new_items {
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
- if cleaner.keep_impl(for_)
- && trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
+ if trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
+ && cleaner.keep_impl(for_, true)
{
let target = items
.iter()
if let Some(prim) = target.primitive_type() {
cleaner.prims.insert(prim);
- } else if let Some(did) = target.def_id() {
+ } else if let Some(did) = target.def_id(&cx.cache) {
cleaner.items.insert(did.into());
}
+ if let Some(for_did) = for_.def_id_no_primitives() {
+ if type_did_to_deref_target.insert(for_did, target).is_none() {
+ // Since only the `DefId` portion of the `Type` instances is known to be same for both the
+ // `Deref` target type and the impl for type positions, this map of types is keyed by
+ // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
+ if cleaner.keep_impl_with_def_id(for_did.into()) {
+ add_deref_target(&type_did_to_deref_target, &mut cleaner, for_did);
+ }
+ }
+ }
}
}
}
new_items.retain(|it| {
- if let ImplItem(Impl { ref for_, ref trait_, ref blanket_impl, .. }) = *it.kind {
- cleaner.keep_impl(for_)
- || trait_
- .as_ref()
- .map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into()))
- || blanket_impl.is_some()
+ if let ImplItem(Impl { ref for_, ref trait_, ref kind, .. }) = *it.kind {
+ cleaner.keep_impl(
+ for_,
+ trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait(),
+ ) || trait_.as_ref().map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into()))
+ || kind.is_blanket()
} else {
true
}
}
}
- let items = if let ModuleItem(Module { ref mut items, .. }) = *krate.module.kind {
- items
+ if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind {
+ items.extend(synth_impls);
+ items.extend(new_items);
} else {
panic!("collect-trait-impls can't run");
};
- items.extend(synth_impls);
- items.extend(new_items);
krate
}
impls: Vec<Item>,
}
-impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> {
- fn fold_item(&mut self, i: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> {
+ fn visit_item(&mut self, i: &Item) {
if i.is_struct() || i.is_enum() || i.is_union() {
// FIXME(eddyb) is this `doc(hidden)` check needed?
if !self
}
}
- Some(self.fold_item_recur(i))
+ self.visit_item_recur(i)
}
}
}
}
-impl DocFolder for ItemCollector {
- fn fold_item(&mut self, i: Item) -> Option<Item> {
+impl DocVisitor for ItemCollector {
+ fn visit_item(&mut self, i: &Item) {
self.items.insert(i.def_id);
- Some(self.fold_item_recur(i))
+ self.visit_item_recur(i)
}
}
}
impl BadImplStripper {
- fn keep_impl(&self, ty: &Type) -> bool {
+ fn keep_impl(&self, ty: &Type, is_deref: bool) -> bool {
if let Generic(_) = ty {
// keep impls made on generics
true
} else if let Some(prim) = ty.primitive_type() {
self.prims.contains(&prim)
- } else if let Some(did) = ty.def_id() {
- self.keep_impl_with_def_id(did.into())
+ } else if let Some(did) = ty.def_id_no_primitives() {
+ is_deref || self.keep_impl_with_def_id(did.into())
} else {
false
}
use super::Pass;
use crate::clean::*;
use crate::core::DocContext;
-use crate::fold::DocFolder;
use crate::html::markdown::main_body_opts;
-use core::ops::Range;
+use crate::visit::DocVisitor;
+
use pulldown_cmark::{Event, Parser, Tag};
+
use std::iter::Peekable;
+use std::ops::Range;
use std::str::CharIndices;
crate const CHECK_INVALID_HTML_TAGS: Pass = Pass {
}
crate fn check_invalid_html_tags(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
- if !cx.tcx.sess.is_nightly_build() {
- krate
- } else {
+ if cx.tcx.sess.is_nightly_build() {
let mut coll = InvalidHtmlTagsLinter { cx };
-
- coll.fold_crate(krate)
+ coll.visit_crate(&krate);
}
+ krate
}
const ALLOWED_UNCLOSED: &[&str] = &[
}
}
-impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> {
- fn fold_item(&mut self, item: Item) -> Option<Item> {
+impl<'a, 'tcx> DocVisitor for InvalidHtmlTagsLinter<'a, 'tcx> {
+ fn visit_item(&mut self, item: &Item) {
let tcx = self.cx.tcx;
let hir_id = match DocContext::as_local_hir_id(tcx, item.def_id) {
Some(hir_id) => hir_id,
None => {
// If non-local, no need to check anything.
- return Some(self.fold_item_recur(item));
+ return;
}
};
let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
}
}
- Some(self.fold_item_recur(item))
+ self.visit_item_recur(item)
}
}
use rustc_middle::middle::privacy::AccessLevels;
use std::mem;
-use crate::clean::{self, GetDefId, Item, ItemIdSet};
+use crate::clean::{self, Item, ItemIdSet};
use crate::fold::{strip_item, DocFolder};
crate struct Stripper<'a> {
if imp.trait_.is_none() && imp.items.is_empty() {
return None;
}
- if let Some(did) = imp.for_.def_id() {
+ if let Some(did) = imp.for_.def_id_no_primitives() {
if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
{
debug!("ImplStripper: impl item for stripped type; removing");
}
if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
for typaram in generics {
- if let Some(did) = typaram.def_id() {
+ if let Some(did) = typaram.def_id_no_primitives() {
if did.is_local() && !self.retained.contains(&did.into()) {
debug!(
"ImplStripper: stripped item in trait's generics; removing impl"
use rustc_hir::{
self as hir,
intravisit::{self, Visitor},
- HirId,
};
use rustc_interface::interface;
use rustc_macros::{Decodable, Encodable};
target_crates,
})),
(Some(_), false) | (None, true) => {
- diag.err(&format!("must use --scrape-examples-output-path and --scrape-examples-target-crate together"));
+ diag.err("must use --scrape-examples-output-path and --scrape-examples-target-crate together");
Err(1)
}
(None, false) => Ok(None),
impl CallLocation {
fn new(
- tcx: TyCtxt<'_>,
expr_span: rustc_span::Span,
- expr_id: HirId,
+ enclosing_item_span: rustc_span::Span,
source_file: &SourceFile,
) -> Self {
- let enclosing_item_span =
- tcx.hir().span_with_body(tcx.hir().get_parent_item(expr_id)).source_callsite();
- assert!(enclosing_item_span.contains(expr_span));
-
CallLocation {
call_expr: SyntaxRange::new(expr_span, source_file),
enclosing_item: SyntaxRange::new(enclosing_item_span, source_file),
fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
intravisit::walk_expr(self, ex);
- // Get type of function if expression is a function call
let tcx = self.tcx;
+
+ // If we visit an item that contains an expression outside a function body,
+ // then we need to exit before calling typeck (which will panic). See
+ // test/run-make/rustdoc-scrape-examples-invalid-expr for an example.
+ let hir = tcx.hir();
+ let owner = hir.local_def_id_to_hir_id(ex.hir_id.owner);
+ if hir.maybe_body_owned_by(owner).is_none() {
+ return;
+ }
+
+ // Get type of function if expression is a function call
let (ty, span) = match ex.kind {
hir::ExprKind::Call(f, _) => {
let types = tcx.typeck(ex.hir_id.owner);
- (types.node_type(f.hir_id), ex.span)
+
+ match types.node_type_opt(f.hir_id) {
+ Some(ty) => (ty, ex.span),
+ None => {
+ return;
+ }
+ }
}
hir::ExprKind::MethodCall(_, _, _, span) => {
let types = tcx.typeck(ex.hir_id.owner);
// If this span comes from a macro expansion, then the source code may not actually show
// a use of the given item, so it would be a poor example. Hence, we skip all uses in macros.
if span.from_expansion() {
+ trace!("Rejecting expr from macro: {:?}", span);
return;
}
+ // If the enclosing item has a span coming from a proc macro, then we also don't want to include
+ // the example.
+ let enclosing_item_span = tcx.hir().span_with_body(tcx.hir().get_parent_item(ex.hir_id));
+ if enclosing_item_span.from_expansion() {
+ trace!("Rejecting expr ({:?}) from macro item: {:?}", span, enclosing_item_span);
+ return;
+ }
+
+ assert!(
+ enclosing_item_span.contains(span),
+ "Attempted to scrape call at [{:?}] whose enclosing item [{:?}] doesn't contain the span of the call.",
+ span,
+ enclosing_item_span
+ );
+
// Save call site if the function resolves to a concrete definition
if let ty::FnDef(def_id, _) = ty.kind() {
- // Ignore functions not from the crate being documented
if self.target_crates.iter().all(|krate| *krate != def_id.krate) {
+ trace!("Rejecting expr from crate not being documented: {:?}", span);
return;
}
let fn_key = tcx.def_path_hash(*def_id);
let fn_entries = self.calls.entry(fn_key).or_default();
- let location = CallLocation::new(tcx, span, ex.hir_id, &file);
+ trace!("Including expr: {:?}", span);
+ let location = CallLocation::new(span, enclosing_item_span, &file);
fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location);
}
}
let mut finder = FindCalls { calls: &mut calls, tcx, map: tcx.hir(), cx, target_crates };
tcx.hir().visit_all_item_likes(&mut finder.as_deep_visitor());
+ // Sort call locations within a given file in document order
+ for fn_calls in calls.values_mut() {
+ for file_calls in fn_calls.values_mut() {
+ file_calls.locations.sort_by_key(|loc| loc.call_expr.byte_span.0);
+ }
+ }
+
// Save output to provided path
let mut encoder = FileEncoder::new(options.output_path).map_err(|e| e.to_string())?;
calls.encode(&mut encoder).map_err(|e| e.to_string())?;
--- /dev/null
+use crate::clean::*;
+
+crate trait DocVisitor: Sized {
+ fn visit_item(&mut self, item: &Item) {
+ self.visit_item_recur(item)
+ }
+
+ /// don't override!
+ fn visit_inner_recur(&mut self, kind: &ItemKind) {
+ match kind {
+ StrippedItem(..) => unreachable!(),
+ ModuleItem(i) => {
+ self.visit_mod(i);
+ return;
+ }
+ StructItem(i) => i.fields.iter().for_each(|x| self.visit_item(x)),
+ UnionItem(i) => i.fields.iter().for_each(|x| self.visit_item(x)),
+ EnumItem(i) => i.variants.iter().for_each(|x| self.visit_item(x)),
+ TraitItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
+ ImplItem(i) => i.items.iter().for_each(|x| self.visit_item(x)),
+ VariantItem(i) => match i {
+ Variant::Struct(j) => j.fields.iter().for_each(|x| self.visit_item(x)),
+ Variant::Tuple(fields) => fields.iter().for_each(|x| self.visit_item(x)),
+ Variant::CLike => {}
+ },
+ ExternCrateItem { src: _ }
+ | ImportItem(_)
+ | FunctionItem(_)
+ | TypedefItem(_, _)
+ | OpaqueTyItem(_)
+ | StaticItem(_)
+ | ConstantItem(_)
+ | TraitAliasItem(_)
+ | TyMethodItem(_)
+ | MethodItem(_, _)
+ | StructFieldItem(_)
+ | ForeignFunctionItem(_)
+ | ForeignStaticItem(_)
+ | ForeignTypeItem
+ | MacroItem(_)
+ | ProcMacroItem(_)
+ | PrimitiveItem(_)
+ | AssocConstItem(_, _)
+ | AssocTypeItem(_, _)
+ | KeywordItem(_) => {}
+ }
+ }
+
+ /// don't override!
+ fn visit_item_recur(&mut self, item: &Item) {
+ match &*item.kind {
+ StrippedItem(i) => self.visit_inner_recur(i),
+ _ => self.visit_inner_recur(&item.kind),
+ }
+ }
+
+ fn visit_mod(&mut self, m: &Module) {
+ m.items.iter().for_each(|i| self.visit_item(i))
+ }
+
+ fn visit_crate(&mut self, c: &Crate) {
+ self.visit_item(&c.module);
+
+ // FIXME: make this a simple by-ref for loop once external_traits is cleaned up
+ let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) };
+ for (k, v) in external_traits {
+ v.trait_.items.iter().for_each(|i| self.visit_item(i));
+ c.external_traits.borrow_mut().insert(k, v);
+ }
+ }
+}
use rustc_hir::CRATE_HIR_ID;
use rustc_middle::middle::privacy::AccessLevel;
use rustc_middle::ty::TyCtxt;
-use rustc_span;
use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Symbol};
_ if self.inlining && !is_pub => {}
hir::ItemKind::GlobalAsm(..) => {}
hir::ItemKind::Use(_, hir::UseKind::ListStem) => {}
- hir::ItemKind::Use(ref path, kind) => {
+ hir::ItemKind::Use(path, kind) => {
let is_glob = kind == hir::UseKind::Glob;
// Struct and variant constructors and proc macro stubs always show up alongside
"__comment": "Generated by `./x.py run src/tools/bump-stage0`. Run that command again to update the bootstrap compiler.",
"dist_server": "https://static.rust-lang.org",
"compiler": {
- "date": "2021-09-08",
+ "date": "2021-10-22",
"version": "beta"
},
"rustfmt": {
- "date": "2021-09-08",
+ "date": "2021-10-23",
"version": "nightly"
},
"checksums_sha256": {
- "dist/2021-09-08/cargo-beta-aarch64-apple-darwin.tar.gz": "5bc2e21b10c153fd070c1a9b9af8ff68ada71f10953d8261bd8aa5f599878db3",
- "dist/2021-09-08/cargo-beta-aarch64-apple-darwin.tar.xz": "95082b292ccf8e0fdd637f591dd3180297c48ec13ccbcb3e1a2c115feb17463f",
- "dist/2021-09-08/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "7de49c4e1db688089dd566647c23233fb4ff21dbb4025a4be37d18b11cc82e2f",
- "dist/2021-09-08/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "35394e3c08a3dd392958187b091b3bdc576a6bf0d2d139556df21cd3ff1d21cc",
- "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "a71153dde967a7816636dce62ba4334baadad4b926b25dc54c068c5cb293df9a",
- "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "d4e33616af35dd7564a73e702eb6eab7eae5da7a980f518bd3d34f4cf0d05440",
- "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "f76545e48977d2ebad75d3cf745d81ca709d59ca02a6c66ee3d049d8ca145463",
- "dist/2021-09-08/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "79cf346367022c3a1ba58fd134f8189fa7781e702871d56f60dc1fff9d318570",
- "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "7884e6a177a2469f21dee177564e03490fc541e877f0a1858e17162a9037298c",
- "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "6fb307038c827d4e915224bc17709929628bdc5eda625644eaa4df992de75718",
- "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "a367fc19f65b07cfec4732d3bd13aa662581d9aca886d56c93bad171948c9593",
- "dist/2021-09-08/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "161eabe9fc1a0031f9fb044da4cc4c2cf376c6a018695f9fa1f5d7ce96c742d1",
- "dist/2021-09-08/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "35587eeb680443f759c6cc9526186d51e35b08683f9c8a112d692324b62afae4",
- "dist/2021-09-08/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "8fea8765c22e9751379585d381ad14aa0faab811cfaf40dbb55a60c82146b91e",
- "dist/2021-09-08/cargo-beta-i686-pc-windows-gnu.tar.gz": "9e7e075e79cfca74b1185067962e3b37118ed32c8258d6746f05891f742226cb",
- "dist/2021-09-08/cargo-beta-i686-pc-windows-gnu.tar.xz": "50f34954765c542076e7a6d9dbaf3a8e8dbfbabfa95bbc76e95eb1fb52e1227a",
- "dist/2021-09-08/cargo-beta-i686-pc-windows-msvc.tar.gz": "eb93a58581ff485b44013d3623d0f4afb0fc2e3a3c7ff1898b74faad6f7bf48d",
- "dist/2021-09-08/cargo-beta-i686-pc-windows-msvc.tar.xz": "1913dd2d4b0c56a6e5ec3686fa03eafc716006cc1fcdcfd81cf1b7984b9532b1",
- "dist/2021-09-08/cargo-beta-i686-unknown-linux-gnu.tar.gz": "04b3f5ca4f4a24a2555c186600f683730a59f807d3525248c1d8f2f674cd00a6",
- "dist/2021-09-08/cargo-beta-i686-unknown-linux-gnu.tar.xz": "c730e3f619d69d221277f3b44a188746980eb7a0c79dab9a252cea6bc4a1e54b",
- "dist/2021-09-08/cargo-beta-mips-unknown-linux-gnu.tar.gz": "94fc426e50671c39d7a272b9636ce43bc3242f1b6a302555914127ab73ce6c65",
- "dist/2021-09-08/cargo-beta-mips-unknown-linux-gnu.tar.xz": "c44957519099e19edfeceed53b99674d9b98731b20ca7494621fb0dcc6488ed5",
- "dist/2021-09-08/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "377a998bba44a16bb401bf56c4be2e38f1c40e37f71335f93ba8e54d20d7a3c3",
- "dist/2021-09-08/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "2406c2ac61d9b494b3a6327d991a6846a18c867fc581892874a2e3e83f4d49fe",
- "dist/2021-09-08/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "52c7d8009a6ca8701912c9e02c1278dacd2b6c2bdb218416d1e3db2c750b7536",
- "dist/2021-09-08/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "764820946adfd6594c7c9c4f97cb06d1c639ae2621ded3059d234a0cef97b1dd",
- "dist/2021-09-08/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "d351cbcd87d10d54bde4311d6fc902a655e8c74ffb16b2a85cfb8e5ad30faeda",
- "dist/2021-09-08/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "ec7235af6ae25ce30c61d06f94bd398018878b741d8d94edad8e3dbaaad0cc2e",
- "dist/2021-09-08/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "11d983f439f46a1b49d72b0e8ec1dd5f78c72c23f305476ce3b56ec20167ccc9",
- "dist/2021-09-08/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "327fcdfcc7679178e734293e23e752d44bf1a4c44a88e5b2d89bfa7f95b7876c",
- "dist/2021-09-08/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "52f827f09376c0f21419cbff1e56d30337d140c1c097d5a38d4541f65545d3d2",
- "dist/2021-09-08/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "e9f956aaa4f8428b813d27c43a8602671a27f567d206f769da7b14e5029f5a1f",
- "dist/2021-09-08/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "b59d4814b99031a9e418fd423833500a3436b65b0696974d1d6a2f7598ecce2d",
- "dist/2021-09-08/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "5751e2453329e1fe2378cf9e7ade93c75df7a31d4dbeb0f14fde9c3cfbc5d5b1",
- "dist/2021-09-08/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "a3d97d9efad02108166878a9a30d3485a9f6db0768bbef5c98e86540c6f4901c",
- "dist/2021-09-08/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "e8c3bf169cdcf9192363c9ace37457a94720d36ff1b607e178796dac933f652f",
- "dist/2021-09-08/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "51fc38135a45870bd01bbcee4b69f5e7055424b1cfa36d4c0272613baf3185c2",
- "dist/2021-09-08/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "bc392d660368c856ab1bc96b603699d492f03b226a0d60812a1bb19ca6c05ff3",
- "dist/2021-09-08/cargo-beta-x86_64-apple-darwin.tar.gz": "ea1804dfe7b806368f278adcb887e4aa023ff7f533bee84541415cb0862ed836",
- "dist/2021-09-08/cargo-beta-x86_64-apple-darwin.tar.xz": "69fa3524d2bb2bbbf0c0a4e18ecbec3eeae791f9b60547d6adf0fa20123c4a41",
- "dist/2021-09-08/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "611c3653a03ca05effb06b5857b77cb24fd87ae5f1d294df980c96a57b8a9a74",
- "dist/2021-09-08/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "cca04b2298bea6b447daa806af2313da4797072d27ecc3202bd0633b5a1d5fb4",
- "dist/2021-09-08/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "763d4ec911a374d348468a38d07caa8d559330c6179f5cd40b5a54ccdb355580",
- "dist/2021-09-08/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "37d24786e764c3af201cba07ef88a27fac97d150d7711cfdbb625e957b9f0139",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-freebsd.tar.gz": "f39494da3f92c39be50579f26d7f09d8e5f985e3566f8742aacc1446ab9f92c1",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-freebsd.tar.xz": "b65f8024b47d4784ab59e4722e522e54442852bbe16906760f2708e2b0d0fe65",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-illumos.tar.gz": "072bb564f73a97bdc6d58970735191d8da0831926dcd155a946f0fde1f382a02",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-illumos.tar.xz": "fc6a9c6d4cceeac868b37e200ed193981b8d70e8408d8e4b4765e149a9075c3a",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "8074fc6912e4bdbae269a334f21d0ead7bb0f28344ad67d71f65487baf21cc35",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "32a8471b2fb91b62aeda637bdb1368c67d1b17daaeea2592517666393857af16",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "19dbfab31784d0615d0e84c526e98d9f47332492744bd1ab4fc7434c0762c5ad",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "510734acf369b92a3f1eb30921a96f393ae207af7dffe6a83df66c350bd1a510",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-netbsd.tar.gz": "85e2fb4ab2ca3eff3ce98ab1c74c996a6b9cd2c20ff3f47c8624e261ac254195",
- "dist/2021-09-08/cargo-beta-x86_64-unknown-netbsd.tar.xz": "2b1cff0bfa9bcece19e61f4be680ebaa05663e918fc9f3a20516efd91244e1c6",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-darwin.tar.gz": "54386650675047126f2b418485a5b2ca8bf3b568231fe54914512ae09809276e",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-darwin.tar.xz": "c7613b2089562353502560a6521139dfd7fd58a96c772877cf2ea7bfd62920d4",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "a80e59fa3885f73973d9c3eb50628718eda015b1e62f328152ee95971acb10c2",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "b0b65575680186ae6c032fabad5dd4352d17ec2d29ecc22771ab9f86a54b90e8",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-ios.tar.gz": "22fdfea8abb345a32ca47ce658c601c36d7838cf22383a34470db643a14e89b3",
- "dist/2021-09-08/rust-std-beta-aarch64-apple-ios.tar.xz": "3a145167eb7bd82e59df7bd009f69f4951efb1487cf002c584625c24be35f4c0",
- "dist/2021-09-08/rust-std-beta-aarch64-fuchsia.tar.gz": "97d1614ad18e71a09326d65ec4bb631c9974f4d3c63c9438b180646579227f7d",
- "dist/2021-09-08/rust-std-beta-aarch64-fuchsia.tar.xz": "aabd6f6c8548b6576986f6fa2632ced035f0ad504da05d3dfd92ab0202104ff9",
- "dist/2021-09-08/rust-std-beta-aarch64-linux-android.tar.gz": "5e67121330fd7e095f86c5dc71bd5180ec1669ad819ccf0bb4b38b46f35bcf94",
- "dist/2021-09-08/rust-std-beta-aarch64-linux-android.tar.xz": "b3d72ba51cca485d742117c70915a5e57404d3f8c80356c8df388eba913e136d",
- "dist/2021-09-08/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "f3eaf16070eb770d464a844e72257cca4ccce4ee2c380f276e82d259d8781326",
- "dist/2021-09-08/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "846480e3eaf8d21fb4d99659a68e71259da613e54cfd098470c139e38ea5a447",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "198be5989e4d2d479582ef2002ec3041105555cbb86488ba563fce35ae1c5c18",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "706148bf9e562cf61d6f882a330e0fd150eb0593136a370cf559c54b6723f4c1",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "8e2718c2509c3db0696599dbd93f7a9c846228374ec0e24bf9f7b876a7714d71",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "e44e11ca1ac94d2335c19891fc8b85394b3935a86fa51c8a2c558faf8606c7bc",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "9439bb56b5c11e9fab00e02e7f931c4582a6dbb3aeb7b20e5ad0fe5420dd27d0",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "5e3187685291d52c500aba70de657478e08b5a69ecbf381f2ae41cb78cfd82d3",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-none.tar.gz": "69c5da7ba93aeb93f8f7a6b581f1895b427c377c8f624274cf2691cacf845acc",
- "dist/2021-09-08/rust-std-beta-aarch64-unknown-none.tar.xz": "8d66841c5e9e20d35b3791bbd10fb97e73b7abf602fee52a939a7096e0040eb0",
- "dist/2021-09-08/rust-std-beta-arm-linux-androideabi.tar.gz": "4901f22f057d78331d298c23b66a39b2caa39580b19adc007fa8a4780483b27c",
- "dist/2021-09-08/rust-std-beta-arm-linux-androideabi.tar.xz": "ba5d5016a625f433dc2fdacb3a1c462a08cdf9cdfcd202a966f16386e58362cb",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "0ea2986826d17ea1baeecda1c73af27e41830d22aa10722ac18e1427a3c11295",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "11e8397c3b6cc2f0ce7c8d725e8bc8dd0a7b7c800174ca3f4da6ee4c32e338e9",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "019fb984e383342a3ec4069f7f62bbc33c9b9609202b571ae32fe6b0ddd2dd60",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "e86d5310c9181ccfd432bc93e6715d109f26608bea97fee0d9f0d2efaaa7126a",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "1a7c7bf25c54c9a394a671d7f23e5cb08d6501b25bbb687159a208dfa16b0d33",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "e8deaf7cf0031d73e93ac1f61713836a0413f644639f8f602d234bd583c660c2",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "0d72ae75cc1b59146dd799cb85a8c60ea9c4169f53f17b8eeb74da644bad0e21",
- "dist/2021-09-08/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "1dd8c951a7e13e68686e9a9a3eb0ecdae83fb178454a0ace9c649b5b47fc9a50",
- "dist/2021-09-08/rust-std-beta-armebv7r-none-eabi.tar.gz": "8b4b4163b746618c2dde450a7151ccdbfaf9732311fb959d11336bd78bfa8d25",
- "dist/2021-09-08/rust-std-beta-armebv7r-none-eabi.tar.xz": "fa6ef79c9a3ac07c0cebe908eebab2a32f578f0838c0f939bf8f4136aed7a499",
- "dist/2021-09-08/rust-std-beta-armebv7r-none-eabihf.tar.gz": "487c64e8251564373437f94b5e94d81bec50b61e77c39c691ce912cf95236d0d",
- "dist/2021-09-08/rust-std-beta-armebv7r-none-eabihf.tar.xz": "2bae0e0b2383ee6182ce8df4dd26993aaa56aa4dd89e6cac1982a48414ca5d5c",
- "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "bb5ca2b48383b27d181d90e4802cd387cacab9c00fca853c0deeb317270851b0",
- "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "f7bf769be48434faddf3dbed8264b1ab5dbbb3657f5b71640ad9330b3340ca29",
- "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "c88db813417a1263408cc3bffeaf03b45db7b2c0a89c8441b3f4e7514473a0c3",
- "dist/2021-09-08/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "3c5a3ea4ce9a6826dd3fc1eaae8615701bf3b5c53d56fe6948432229f027ac1c",
- "dist/2021-09-08/rust-std-beta-armv7-linux-androideabi.tar.gz": "3d45d64267149d222337421be4cd5207812125f9b2df253f507f0cc2cba37219",
- "dist/2021-09-08/rust-std-beta-armv7-linux-androideabi.tar.xz": "ee71e74b369b42a9c2258bf5d9c8c7119ee65b8951d4655c477a4593ec2cf3fa",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "949bce55fc6047a37f8ea26e21cc69557ad66a45c688442f2be06a8cab503358",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "28ec52f486459b436c0097db2b400a202ad1280591f2612cadf4daec1ef4e4a8",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "0f7782f0b6874c858de7171d255f12fe309e9255ad55a6406577feae3702fbc0",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "cf3bc863ecd6da3fb45c3d2f5b6741d57ff778b1bb2e4f0d05480c9aab480bbf",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "35e3647a940d2e2e37ed3a5b7c1a789f94b7f1a256f0bd339630bb7b0342c2e0",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "ed1ec913fd3e821501e52be1d3cdac3fbe5a6c00acd17204b1891aa5fa3e6f93",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "2fc9f5791717cc876d155f4cbb672dabf9fa308ac67636e50a75a5b5ea11369f",
- "dist/2021-09-08/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "91ac6c321d172cfb62e6772c2c7340110fb9801a8d44814b69b477f611f09c58",
- "dist/2021-09-08/rust-std-beta-armv7a-none-eabi.tar.gz": "69661706ec6749f851d6a967f69fc8e4de8e5a58da2a771129b22202918f6ce8",
- "dist/2021-09-08/rust-std-beta-armv7a-none-eabi.tar.xz": "45275aea14a3f4547e0e2f11ce2cf364ac2c749cf0df467a54e27b39b65a5fe2",
- "dist/2021-09-08/rust-std-beta-armv7r-none-eabi.tar.gz": "63ea71e69e36d916baca6eb42b4b4b6f2f69870063526533a2699f66fc0cb317",
- "dist/2021-09-08/rust-std-beta-armv7r-none-eabi.tar.xz": "2d6f4ca658991a7b426d50330371922888706944eb3c1603288d4be2fa4f5457",
- "dist/2021-09-08/rust-std-beta-armv7r-none-eabihf.tar.gz": "3d27ea42bd3a419ccf7f28b9ff040e077f3e963948924f996aaf718abeeb1709",
- "dist/2021-09-08/rust-std-beta-armv7r-none-eabihf.tar.xz": "8f6bc34715629354b4d9f71d7a8693171b667604d237b433f7444df1228d2a36",
- "dist/2021-09-08/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "f83bdc7e73590beab7ec915bb7a3a7531e485d7f73cf9c65150102748207d874",
- "dist/2021-09-08/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "1068750fb0b4a7ec35b5674a6c7fb0368b043bee6df0fbe360f521c7c2f08b94",
- "dist/2021-09-08/rust-std-beta-i586-pc-windows-msvc.tar.gz": "506bd86d803953bb086e057c6b2ee1fd9ffa0e08a0d7162189119cd21668cc0f",
- "dist/2021-09-08/rust-std-beta-i586-pc-windows-msvc.tar.xz": "b608aff18260165b51acbc06d551c5eb003928f2c7551f83a1ac1782442826ac",
- "dist/2021-09-08/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "c90eca1f2326cfa916e225199e2526719fc9b6f18e2b789366a9668a52eba339",
- "dist/2021-09-08/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "ab382cc6c67bceaf76555a2c71c5f26e46802fe7c2713e173744b14371b742a5",
- "dist/2021-09-08/rust-std-beta-i586-unknown-linux-musl.tar.gz": "dd52e44df6cd8bbac61d484e574d363125662fef270695e962900995a05818b3",
- "dist/2021-09-08/rust-std-beta-i586-unknown-linux-musl.tar.xz": "e9c4bba480b748625898dc047b950a142ccda9e9fe1e329365741f09f640e843",
- "dist/2021-09-08/rust-std-beta-i686-linux-android.tar.gz": "bb2e1dea2aae2f726420d8a5cd112f1bed6e06e95053f10c6497b1be878b180e",
- "dist/2021-09-08/rust-std-beta-i686-linux-android.tar.xz": "df15194a40cce8c574b219164b75590ad9c55c03ab811682ebe89db004c651f4",
- "dist/2021-09-08/rust-std-beta-i686-pc-windows-gnu.tar.gz": "c7b38618dda1cd13d52c59bb9a4632458aa7b20d90b01478fb506801c3fb41eb",
- "dist/2021-09-08/rust-std-beta-i686-pc-windows-gnu.tar.xz": "83390b595e3273f0b02e05878064429a1815f18bceb7e0d77a63c5caecaebfeb",
- "dist/2021-09-08/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e7c6c8e5ae9d02e9f3c33b174862d1d6e0caf357c7c3cd510e63cc3472db816b",
- "dist/2021-09-08/rust-std-beta-i686-pc-windows-msvc.tar.xz": "feb49ed3fdf25d7703134afefc3c04b0ed23d87adc02945bccac4b30c425fa16",
- "dist/2021-09-08/rust-std-beta-i686-unknown-freebsd.tar.gz": "f633cb1bd2636eceaa87d98a214aa73907502aa92d4cb1a1869870c9bc6ad23a",
- "dist/2021-09-08/rust-std-beta-i686-unknown-freebsd.tar.xz": "cd61b7dfe7ead85a79469008717bc52cb76572fc9688f82a50f07b0c7e0fafb2",
- "dist/2021-09-08/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "b22f1285e8d179a372060916bc2a6d609499231f805b5cec2ef8d1e5d0c70d71",
- "dist/2021-09-08/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "24fd3c052bdec08615e54438fbccd9e43c9956d25b1bfce6f3640eb164aa6f5d",
- "dist/2021-09-08/rust-std-beta-i686-unknown-linux-musl.tar.gz": "df63f460486eeb9a11ed53c35814495e931492aed5abe44a841cd7a43a9e3719",
- "dist/2021-09-08/rust-std-beta-i686-unknown-linux-musl.tar.xz": "3ba2d402c01b099b89518acded3734a552f64a330a7d21732ce641cf25cd5c8d",
- "dist/2021-09-08/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "4cc5b2cfa6747155a0e0c6a7a835abd464bc9610fd071197af1ac50ab8f2fa1c",
- "dist/2021-09-08/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "28f70f287f4cceba042b9574b16ce0403d73785bc6261c9a6739d770d5f354f9",
- "dist/2021-09-08/rust-std-beta-mips-unknown-linux-musl.tar.gz": "04a8dc4e8144330f326dba5182928cf91c50c4b3513df0b67d55d601d3524a7e",
- "dist/2021-09-08/rust-std-beta-mips-unknown-linux-musl.tar.xz": "06a91efa4f8ab42c3a0f9c2ae9279da87bb2a239f1032d1faa3583febace37cc",
- "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "887728123ccd4bb75f4d42bffc1d2b7f46d8bdc4554a77b12578507cb44e7fd5",
- "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "987598a67a36f428fa8fb21e0239aa345e952a1e6c64fefcc2fe2feda56bb864",
- "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "2110b1b7456366668e093d27013d7002e302c6ecccff63c147c0346cd9a452b7",
- "dist/2021-09-08/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "d6f16eca6526aeeef3ec7d0a9948ff5da3b7eff6e4bb9203a9546037df1f8d55",
- "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "36a510c2a8fbc751416183b88680685c232646289504d2e2422e5208cd11670b",
- "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "2f2a7a533d30cdb437bf31d18fb547680d646ec1765ca6c5fe16e449dbf3b613",
- "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "09472066c8403c059e9d34ac2f7a4387e61726c45dd5ff2bc03b85543d8376c0",
- "dist/2021-09-08/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "83c4a0f9ed4fa2884d1d193b79693c3af4e9c8603b9a1f3bd6eb827ba09a5466",
- "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "739998734f48c9591b7aed3452d8425e2c916d202341ff63931fa473e3eb9a25",
- "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "83be5e72fc8597f51c6b2cc216d90c8dba6be509b44fa25f3d7d285e1c54c7c0",
- "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "0a02455697ac62af66b359d5b73436ce7b18274abd18ffa13b7f0f9c1df72f82",
- "dist/2021-09-08/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "1cc6fe6ecfe4c10c2957806e56c1a0aa256ef5bb3ad4ca47f24aae42cf0fc0e3",
- "dist/2021-09-08/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "f90d70acfa78388fe8e54a62f4fd9e773bd1455b036f6af13a5feec072de11e8",
- "dist/2021-09-08/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "d2c491b6fb62bc5279447e7f5d96fbb679a225ec13d6c96c8f80cad859b0f5f8",
- "dist/2021-09-08/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "17e9bca285df96b3bcd48297c89c096aab6b545d783e261103f7b364c214c09d",
- "dist/2021-09-08/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "d4a8679af46449daa4db0acc23bda23aa5c8f35fb2ca9d0e065b35e30d6fc649",
- "dist/2021-09-08/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "845cab4436d36b6eb2a914ab7c48bd49626a04053eee918fbbb78aba1d1e0a4a",
- "dist/2021-09-08/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "b399647f0d9e8458570e8a9ab11b30d7258fa396ab019037b5bb391dbe65ead7",
- "dist/2021-09-08/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "6c84662ba3c210b9d7c3332473cdc95dcf3e238d9c9010581accfafa37cdf4f8",
- "dist/2021-09-08/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "594aba2abb126a615c93bb5c7927eb5a2ccdbe4c54c22bfdfa9cacf99e268889",
- "dist/2021-09-08/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "439f5d5f1d2ee9db18c6e3b0bb831b037234852067a91f1a15bca38ca38b7a0b",
- "dist/2021-09-08/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "227fa2ff323d20a2a8c29e0167fac78c7b88b8db3368b009b75d4a1cd49b7b29",
- "dist/2021-09-08/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "5055560e4dc3df90bf127bb5133c8d2d0ba662c1b1b20d63453cd60ee3e04947",
- "dist/2021-09-08/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "df1267905fe5a23c2ddc47fc0ade249bd663e6d3e8982193cb2a2a638e747e5c",
- "dist/2021-09-08/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "2a702d0d0a0e2cf17a42eac549bd751eadc4398182f42590e3322cc7420b4cd1",
- "dist/2021-09-08/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "98e5d336ee07556ff0fe01f89f9059cb977fa36d5f87ee8633aebb5fa6c8762b",
- "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "de64e6d171a2c11e16142b1e964c0f0e0d6e4bab2e9e9d5d8121ee77fbdb60de",
- "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "1dbb24b1ed6510f098f63933a596f1f58907c22320eb79394dce341af7d7b59a",
- "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "66af911664286500164db018c0aad12a85da035fc1e2d6cffbe7603ff0145624",
- "dist/2021-09-08/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "e8abd1f9f7344842af5f6a85d75404c1589fd17efbe5a8008ab52f082b7b3772",
- "dist/2021-09-08/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "a9f06d8862f9bb805f438b1c01464dd7a9cd07ecd04b1246727ac290891da54f",
- "dist/2021-09-08/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "6143b4b36bbdd1c56b978e9a2afc012163610fac7b8fb9bd9f24abb4e970b21d",
- "dist/2021-09-08/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "5cb4c0616056f36c7cfe446fa97e146fd5c525be1de8bbdb5017ad0d07a9561d",
- "dist/2021-09-08/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "9d2397f9d70956ddd50b37f8a7dba71d3cea9df5fa128e35d92cb162d7f938d4",
- "dist/2021-09-08/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "b7e0fe340919a37cf8daeb1a747392c53fce4dafc84331f998479c3c12572973",
- "dist/2021-09-08/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "464b2601346e014b2f5a9cc64dd32897be915742a5c75eeacf82691277c4f8de",
- "dist/2021-09-08/rust-std-beta-sparcv9-sun-solaris.tar.gz": "40c61118e3e85343f6ea3059e41e3d2e3108f540331d8114948447307eea9b5f",
- "dist/2021-09-08/rust-std-beta-sparcv9-sun-solaris.tar.xz": "3dfb77e1315a8367b4a5665ae9419843a8cb953ce4726b35307e7c7199514616",
- "dist/2021-09-08/rust-std-beta-thumbv6m-none-eabi.tar.gz": "66632c7fad29f275ccfed907e395db12e621b17909e5e026d192f0b552fd4be1",
- "dist/2021-09-08/rust-std-beta-thumbv6m-none-eabi.tar.xz": "a308cdebc35d65d8208fe2b2dc7b45dfb1a64405478d86b82bfb28115174a129",
- "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabi.tar.gz": "c342b21b5f61dcddea74b89f60f1d0d0622c5aedc79550d316b8744b522bda6f",
- "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabi.tar.xz": "a3b00a6b9b3fb8942700f91d32077520185a7c21d25620193cbe2e730a021f64",
- "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "18f15f7e2ffe97f7be99e246144e6b9ad7445b1b66382112e71e08137a36b840",
- "dist/2021-09-08/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "16eb54bf02813d45c6ff328ec7db8f16daf0e57dedfad7247249af2ec5133d4b",
- "dist/2021-09-08/rust-std-beta-thumbv7m-none-eabi.tar.gz": "14bdada81be2379b2ead0212cc34add3ace87bd222532ada2a00b603180db946",
- "dist/2021-09-08/rust-std-beta-thumbv7m-none-eabi.tar.xz": "f6cfa6bdcee91a6cab748fced0d2be7642b83cbe7d5fdcdf638fc3e86277d17e",
- "dist/2021-09-08/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "e11e35a643c0a9983fb1f1e8f60ac073a4ee48c4a9f3e757f4fb55ea8364046d",
- "dist/2021-09-08/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "2ee5fc11fb01f84e2346a17745c935f75d400a2448ec49d9e3535c98c3d67a73",
- "dist/2021-09-08/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "61b26681fdb6957c3acd9aa32b011605786bed196cd71334d966ad9289efbb2f",
- "dist/2021-09-08/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "bfd3391ebdc20690ede1a8a606f59df9009a473962deb04d3a89b266d0a89949",
- "dist/2021-09-08/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "ae8d90bdd3d2faa2623ec30935e3e93bf3af6ad036eaae72bc8a3d086f7cd054",
- "dist/2021-09-08/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "66ce451e2a0830808aa996b4643fa6ca6d89a072467d9df659ad4e202b73d561",
- "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "1afbb6a4ee9ec38b7ad1c67c3df3371d188b831ffdb58ae96227e5c9a017f5d9",
- "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "8c1e0000926fb4ff370763396e69aef70ed7871c33f01bc2d429abf31ee8d211",
- "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "169852e1ae03792a8f492954258d08bc1483615e7121d587476ac4fc065c79a1",
- "dist/2021-09-08/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "1da32effe4416f0cd5448a9061d57dd2f4b541f737a7036d20d78fd44f715ddb",
- "dist/2021-09-08/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "39d22c8ff2620d4e6569eb75c86d4135a288bba00dcc479f4371a1e7e52fee4b",
- "dist/2021-09-08/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "c34b1abdb8e3f3f913564a472b18dc52b239d7e327a4bd89d9bd0290d0b31635",
- "dist/2021-09-08/rust-std-beta-wasm32-unknown-unknown.tar.gz": "ae284aa5819407e8daf022fbbf1f5d279366077faf25a6653d9c518ab3fe710e",
- "dist/2021-09-08/rust-std-beta-wasm32-unknown-unknown.tar.xz": "be7a5b763db13ab1582a5f98fe7fb9ab1facdd645a7fe4544e0cbec9d1c58e76",
- "dist/2021-09-08/rust-std-beta-wasm32-wasi.tar.gz": "ac9f39cb7924f48fc29d666dfda3c6001b6880d6efd956acfa734389ef7b5dbe",
- "dist/2021-09-08/rust-std-beta-wasm32-wasi.tar.xz": "04d20256cea7b2394f72f6c0895a9d249fbd641fcaf616a628ad703e79c950a2",
- "dist/2021-09-08/rust-std-beta-x86_64-apple-darwin.tar.gz": "c304a11e2361b42f80fb9c6f239cbfbd2b7ffdcf00fe49ac94e3a6d4a9d2d2b3",
- "dist/2021-09-08/rust-std-beta-x86_64-apple-darwin.tar.xz": "35d51256fc42481b8265a02d756bb9bd84a23240156ed1fdf84ee3adaa77b8c2",
- "dist/2021-09-08/rust-std-beta-x86_64-apple-ios.tar.gz": "6eec11897fe08b43fece4a1cf0ecec1ca247b3d01656b4a2a159815fbe13c626",
- "dist/2021-09-08/rust-std-beta-x86_64-apple-ios.tar.xz": "faddd6de72f17f669e38dc2e9ef5cdd4b729cdbccaae6a7711c54b173d86bfd2",
- "dist/2021-09-08/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "6741696a588c4e723d279e388d446271b773c6029a823c5e2135a08a018c6083",
- "dist/2021-09-08/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "a62d276ad6a4832cadd3ef4c587cc77f588774b93b2807dc1ab9e0acff037838",
- "dist/2021-09-08/rust-std-beta-x86_64-fuchsia.tar.gz": "38a61746734681a97e84419709bd3ebc722207db656737e7be75479e0d991f9f",
- "dist/2021-09-08/rust-std-beta-x86_64-fuchsia.tar.xz": "b85bbcd1353315e5c4eef82707912566f6a1f94f706350ae0474a29ff33b603e",
- "dist/2021-09-08/rust-std-beta-x86_64-linux-android.tar.gz": "de32ea66a8228857a34f39d8d47e6cb32a4db9efd73100e97afe12bf58f6d520",
- "dist/2021-09-08/rust-std-beta-x86_64-linux-android.tar.xz": "e2f89e63a379ba8182acf1b4fba33f790e0cdf4675bc46239840ecde613b1835",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-solaris.tar.gz": "6136d0607905fe49617a8171896bfada258eb84cb00e8042fd67bef29732a714",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-solaris.tar.xz": "00a98839ab7d2302feeaa0fdbedc169bfb2bd7229c27aa274954efc73b52c4f3",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "2f711c4a26ed3b876e64e256bf1b4040552e80a06bec352a9d3479ed8ed6aca9",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "e479e495292512d67414d3056c322ea368559a0d95d827f944bae7382bea4e4a",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "ce43642d886784242a3914b799b1a77b60df642af2a41f75eac186b7f1b6104e",
- "dist/2021-09-08/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "a83d236d59f04f3a51a6a34ccf7b79b4b2f269dc50e147d61e1e9c4a57925835",
- "dist/2021-09-08/rust-std-beta-x86_64-sun-solaris.tar.gz": "a8e7f979fc8ad5bdaa4ea2965c305a3296dfe88ffa235cdb7aea8234e4a46138",
- "dist/2021-09-08/rust-std-beta-x86_64-sun-solaris.tar.xz": "72ed0fb32e53b283c6a0e1752d231915b98504164965f7e2b5f06d8550e4c338",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "1f5535f9d44afdacf059681587239bf4d21985f1dfbd3ace94c864c2d7616a42",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "5faf349a9cc231c144c52de40f2a487a935c6f6146614547e64cabb26f037a23",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-illumos.tar.gz": "0ae64780c9a944a32bc51b5efef9f0818025a423819ef60fdc799945d52bfd73",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-illumos.tar.xz": "b3308afe75af668878959db95b039c6e1c4416badf67ee650b07f5cf07f14ab2",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "f8078421bde37f74dd0ffe0ea44704778baca779e502cb760371340a6bfa15a5",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "cc26d8fd139b35e13cf75c2942727bba7899a874d95f865c127b0c3af15707cd",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "6e0ef50cb8c4ce19d7de517ad51581c4d80043fa489278c0ba984a5d408269db",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "5c9380fb472de93ebfe59b21f2a74b5f19a632ef6eccf77a89cf0b26ce2054a7",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "264c78d59e71d4fa232f6f10713ee61d94c270e493eabad7318877afa46b7327",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "af3e5b1883e8fa7d49e64ce8754d656d2992eba33b8ec5f92245f2a82793abf4",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "0797448414c3421577705e725814dbf833a44b0930875fe418aa1eed9ebf6121",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "bd3ec2d0fde1e11a75bfc3b684c2d564bd5068519d1c5a382ae09379337236c9",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-redox.tar.gz": "449ea2e6ed2e1b4d656f8da8390f2e22cbbe40713e5f91cbc85971f36488402d",
- "dist/2021-09-08/rust-std-beta-x86_64-unknown-redox.tar.xz": "5424c5b4aa5588de73734dcd43cd1ff9bf0e0ba244749a1519afc94c8f2057e2",
- "dist/2021-09-08/rustc-beta-aarch64-apple-darwin.tar.gz": "b14f7853a9353b71d7babeeb136fbb595b5c23144ac1bd72e70b74227a1685ca",
- "dist/2021-09-08/rustc-beta-aarch64-apple-darwin.tar.xz": "af2ab319357b3b4a2810a52c824f8f308d2c3f41ea1ed30ba9ef9ff6a4769dde",
- "dist/2021-09-08/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "c09a6bdbe6dccbdcd366a695d54be4e0a472fa1ca5bf30bf7eaf389534e2f70c",
- "dist/2021-09-08/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "9fad7bc10840340081cd29166aa788843a9950e293d6ced71a26e36bf0eafe9e",
- "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "d20cdcc681b0506e73ccd0b484a7b7394a08615d2d195318d0f2c5af3063581b",
- "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "07d0b4393149f854dca2d622a6ac8d6cb9fc62d2d24977bcf50cdc1824fe6a32",
- "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "dbe81393d5253521adceda8027b103edef45a031120e92f2e9e89564e85863c2",
- "dist/2021-09-08/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "40edabc1e00f228815c88798543f55081e3dfe352f88753f5592479de9236b4b",
- "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "114dce61c5bf25be9f3cb33cd0c7500b1a60f5cbebef27547458312b8ddb8f4d",
- "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "abc9130f7116badf9949f5a3ecd6820787e40bb590ebbd5c867b05cedfbdce5f",
- "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "cbebd112f0dd96258ed19b25762af60c9bac30669ae229d6b8456049779c890f",
- "dist/2021-09-08/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "cff6cbf35aba285cfb5f5d2f8a9dee5edefc7c22843ae0198e693993d556fcae",
- "dist/2021-09-08/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "c20cf9a2e72f712f02ed867e9c4babe02d7ff22d62eb96cb127054010b6731b6",
- "dist/2021-09-08/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "aa1b6cd4f9153fba338eb5c8a90ace06d742c97e659c3ffbca75125e5477b828",
- "dist/2021-09-08/rustc-beta-i686-pc-windows-gnu.tar.gz": "3308d1e3ee0ae40f8db301601c73bf6eace168b570e9ab952760e28bd970a240",
- "dist/2021-09-08/rustc-beta-i686-pc-windows-gnu.tar.xz": "0a019f66979c2542bf9fb268bad143cd55deac6f1502a4393464bb26a1e21c76",
- "dist/2021-09-08/rustc-beta-i686-pc-windows-msvc.tar.gz": "31016537cedf38ef83e29a6125445946834a06ec2fda51ef799566baeb47211d",
- "dist/2021-09-08/rustc-beta-i686-pc-windows-msvc.tar.xz": "a997b98b7a28358bd4ed394ddd3af62e5b19d7a33a61f55bf973b06fb9b95fe5",
- "dist/2021-09-08/rustc-beta-i686-unknown-linux-gnu.tar.gz": "ddfba3dfb711db2ebb4cd7149172a738200b8e38a98f7ec5e5bbc81515be5453",
- "dist/2021-09-08/rustc-beta-i686-unknown-linux-gnu.tar.xz": "5b0435f652dc749216735fc06599a3c6916a867ab82dc126d0cde872855dac83",
- "dist/2021-09-08/rustc-beta-mips-unknown-linux-gnu.tar.gz": "6408766f8c58c13ba51347375dc5ed0fb7c247c8aee9b8a89e3369c70541c397",
- "dist/2021-09-08/rustc-beta-mips-unknown-linux-gnu.tar.xz": "18a41553893aa8ff4c80fef252e8ba80c383d2809a57123fe89e89172a5839c5",
- "dist/2021-09-08/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "28078984a80c4cb0e65391ae213390059a9eebff028209861d23c82b4db0a11c",
- "dist/2021-09-08/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "277cfaafab145858ee5102a657c597abbdfa33ed2d6f1c8806f218bad91b2d8f",
- "dist/2021-09-08/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "8c8c92719f3d299047089031cb29ce209e2954466415449d37d474e88a732d8e",
- "dist/2021-09-08/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "d055a61cd0ec951edbc703180c190ef4dbed3391d1b2472668340642e205fecb",
- "dist/2021-09-08/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "95433c7dc0437f61a024276c10a0654128bd0e873597932297140f82e34ad201",
- "dist/2021-09-08/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "a3660c9909e3821537a275e37121950d6adbc87b85959e80fd7b72c6e3b7b944",
- "dist/2021-09-08/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "07384f5fba55ad572753fc85ad6b2d231d94b31f009defb694c8632b38eeeb62",
- "dist/2021-09-08/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "f0985ea483fbad75a9cff021db6c230c5c322eff942da667a0dd6cb3e37bb2c6",
- "dist/2021-09-08/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "81a7ddf94bf62f45dde9199df8b28ac9971d23b1817906e119ca4ea32000b08d",
- "dist/2021-09-08/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "7ce055fd68b1c5e3c48c9f03289cd4eb3af619cc30a7103056b20fe842a92db8",
- "dist/2021-09-08/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "6b853d5c2fd2dc61d89c26bf5b365f48a9c535dd30aa672f28f254af8fbcc9e3",
- "dist/2021-09-08/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "32c659ea9578759020f291099f16b1d12eebae30e07d35568e69cd0721576c24",
- "dist/2021-09-08/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "a73a918ec89b759f19b605df527471acbbcfd2e3debcd0601d7a3956f645bcf0",
- "dist/2021-09-08/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "eabdfdac435195844bdfaaa5f8bf6b57cf045742c6180c3ff0822bd85fac40f5",
- "dist/2021-09-08/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "a626ed9d5ce779e7fd8ab17d4dc83130a57200669730851bc68eb01d88bade7d",
- "dist/2021-09-08/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "67f195e60d88b3e0f1a702f7ba0cefded2dca6ffc03ede1f9b6e4fd38592eb6d",
- "dist/2021-09-08/rustc-beta-x86_64-apple-darwin.tar.gz": "01e5b6d7153866ada9d3c1caee5c95da58296acd7007aa93338171cc349af304",
- "dist/2021-09-08/rustc-beta-x86_64-apple-darwin.tar.xz": "a0b87b79f87e97a746ad311f2bf36ee9d5784f504f844427415e4a983ea4a0ac",
- "dist/2021-09-08/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "54ff5dfa917a5ebbaf77185d4efff9700d248dd66746dcb3942e29917495dd3b",
- "dist/2021-09-08/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "2d9dddd6b9a3ef6c5bb0758dbee171f08882292ba17e1f98445a9cf196f9c02c",
- "dist/2021-09-08/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "359690df63e15260f028d6838f4f5007f828c4a977cc657513b8ab6900f1d126",
- "dist/2021-09-08/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "6d8d2b9d5964fe690d4f6fd7ee643bce5f049d19e33c7f3b580502ba83ce5ea5",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-freebsd.tar.gz": "5e47aa933805000f806984b09222808636eddcb58ea0b95913eae6c4f0ce913c",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-freebsd.tar.xz": "4e01128800f479a96597ce7eee9d2e76a5128ae1c13a4e0e2eb52e36d43cf559",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-illumos.tar.gz": "51cdd463ec6402dac5a4b0ab3b0e303ad97ba49c2a63e1cfa2d8036d060fd67a",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-illumos.tar.xz": "498cca6f9826a9180759a0446627e2e6dba50b6bf1051044e6e09dc714d7b3e7",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "59314c4c868e57a76f7cb4dd80cd9a7e6230b87080784db44349420c950efddc",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "8b3e2cdba3ff86144029f7c7446825dff79937ed8a30df15a33a779e9f694227",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "56dc8f8914bbe5beaa1e369fdc22d99ef98c9d864e24f5b7d64cf6188c400b1c",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "66cf18df72034540d756b29d69a4148123029ff512fc831a786fe15a9641382b",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-netbsd.tar.gz": "2315fd067e858501b4df44f2a4d042cef3f70b7314ee6cfe24749849b8d386ae",
- "dist/2021-09-08/rustc-beta-x86_64-unknown-netbsd.tar.xz": "62b429e67f24365963b0744e9b4807ae2cb7aa280a5e425882e4894a2d3225fb",
- "dist/2021-09-08/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "691922fb32f3da37532bb9be974ad1717af521ec2b71bca4bbb5e57f3c4cc3fa",
- "dist/2021-09-08/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "2c9667209094b7a603d50d3dc684c505b2ab855c64dcd8b23fe09248a6e13cee",
- "dist/2021-09-08/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "daee571bf222bb7addf0d495991acf3f5001b69bb97d31bb43f0466b4e43c600",
- "dist/2021-09-08/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "f6d31e21f798427c5483256d54b25b6dca1d61ff8c601384c62648959ebbce25",
- "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "98b2eaf259a1bfdc70e40a52e891920dec7fc6132ad8d2420f91655c793ea340",
- "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "a97c1c2646f9628fcc92818d21f4925568681976727686701116d0e6a71693a7",
- "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "a4df0726fba466a5180471d3e63735c2b5ee9794e9f42026b1e8ae404dd43ab6",
- "dist/2021-09-08/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "92846ab58a75bddc0270c9f42234a6585edc9a382e2018baa776aa74bb13e444",
- "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "a8dbc2a00d359c95f05b0b3cf08a12b6df9f888157ba57fa9ba4a134cf271075",
- "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "44b17a06b015f9701291cec7e60b0932c5ebc29244f4a6e35736e9f5ccf47c41",
- "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "ee54b0a25f061c29ea22977c7d36d6fa6bf85abee3b108135b53bcb37028af0b",
- "dist/2021-09-08/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "0a721d2526a78f7e70f9a6c49d156b1c18cd627c066bc8f09b084910864ec252",
- "dist/2021-09-08/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "584ba68113add6e113cffb5c93a8000cfea16d621ba337dc68cd4d106f5e2759",
- "dist/2021-09-08/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "e450429fcd37f15b6e200f62d9cb4790b39b7227e0246b667c82fa3b9ecf1b75",
- "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "e0aa68b96699402e7cc09329055826f63ac9899cf22828d56cf393476a70405a",
- "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "6f10f279f81c35c718446e837f5f22fb61841c45f5172abb2d0d4a035065edcd",
- "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "aeb05fcb66830d395bf9a819a05a44f179cad3f35016f76fa60a4959f9e3c69e",
- "dist/2021-09-08/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "351ee1490533ac9fa00a21c6db6087cb498b0034cb21358d29a8b944bf0f77e3",
- "dist/2021-09-08/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "418b0481fd2b074e9a0f195b9e07f888652642aced34136044bad997f7500802",
- "dist/2021-09-08/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "90d04308cbfc845462687206bf13182d907afebd02bdf88cca9a27eb8f1e7e28",
- "dist/2021-09-08/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "0d2f54c9927ac9de3c00f8f703d52d8310d1b36baa84dbcddf1159759b4bff06",
- "dist/2021-09-08/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "7f2b33077267e6ae064b12c7d0082115ea7f011f168f0d0e3ad9dc7ac9d39705",
- "dist/2021-09-08/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "bdc9fa2cdb295e453460f1bf7b12efaa673955c27b01f22df626de989c3e1a28",
- "dist/2021-09-08/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "bacd376fe18068010ada3e52c531de5a07dcc8232f988feb9e90be59986efb3b",
- "dist/2021-09-08/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "fdc93a8295c563be29793d36b6b1e25f579d187b7e234ced6f17b1fe3c1fac02",
- "dist/2021-09-08/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "289fd400d4959968c0ffccd787d613943c8534527913d0dbed69e8a7251ca32c",
- "dist/2021-09-08/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "2e655b764843cea5f0e70e2a5b2a0f13dd5fa65c4055f42c547e36372af08296",
- "dist/2021-09-08/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "07f6657648d1d7033030e9e2d05bfb9ea0022e63ae72320074a3d09ac9639d09",
- "dist/2021-09-08/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "b78878ec58d6b932d3d1f8e1fefdb7871b1404c701ab0d2f8645246b458ba650",
- "dist/2021-09-08/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "dfa79cb51708794d2c814bff6a60a63ca5358df3670179f9a9ae828811e72ad8",
- "dist/2021-09-08/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "017de1a82a0e3988d1216771082b5d0e3e083dc51d4a0f0266f1e610bac166da",
- "dist/2021-09-08/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "a0a46a62b9af14d2147939967e545ad812d9acebe3d1ed861321a6dfd8d554ca",
- "dist/2021-09-08/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "54dff0daec5dd2a2ab23cf4e92bf9b2d71839c37144b52e5b5aa899ddf027bda",
- "dist/2021-09-08/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "e743e45dc695e0bd9a1ce5fdd183f89951a329ec433bb510d37c47b435152a7b",
- "dist/2021-09-08/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "0e04ae69e03d9e7e8d1d60a265c7ed3c3608a19aaef6ad4aa7ae2b280d3552b8",
- "dist/2021-09-08/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "6ec865bd38b0fde2c9c823f4cb110b96c2aac4f7976cc2a6be48ffa214aa4bc7",
- "dist/2021-09-08/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "3b833517415dee73b1e0d381df441a96856e3bac77f101545624c382aad7902c",
- "dist/2021-09-08/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "7a8a447cc2167d0a998ad3858dfec88beb8658043655087d208affbc94aa3e62",
- "dist/2021-09-08/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "20de8ad3aa7507dd9657c4a4b959c38cc7f732a87bb757183033f78a96288e45",
- "dist/2021-09-08/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "99561b207ba61b455d1522d95143ca4ccc6474187be2f38f1ebff2ed63d0092e",
- "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "145eb25cc3b295060c5f5a354ea2321cd39df17ea4e3a5c73c3eea105f7454a4",
- "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "356ede5cd8a7d51f9e25a54c329b1be1da7d6fe418cbe86fdae9c8bcd9970ac4",
- "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "0cc0f10763b73c5e4c8bdcd15a563d7e9d705b192ed6e8edc50dd6a71b874761",
- "dist/2021-09-08/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "d734aefabe95fa03710dc75e9851c8f2e654f19cec1381ecb18281837d19db38",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "e1c28472a81312560ca36719f0b61b7212a07d63e85d745f97cd8e3b9ea8f191",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "4d6a62738f842e54666c608a466c64f896097ffa65d10d30361704e4b8496eed",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "75b21690480f6214ed174ca86297d9a41f37731560adf5782ccd7116b0df583a",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "5c08f45f557da789d39bf203dfbcf2667f4196dedad327a19dc3ad5bb783079d",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "a7d579672b94978e8427584f7e9d2b6534f320719252db46fc6ee85082d646ff",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "6ffbdb558b9d25e9d923534413b25dc99bb5b9cc92b4774d5255cf70ec20b20d",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "fba0e7bc1401b830223b5207b63808e28403f48d1591c7d47c1681519c1883f7",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "644b3acc47cd7bbbb5405683ce94e7f32a8313ad265da753026bdb6c3687b608",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "3f152caa88299ab8aca2c6d39a5e36af995b95e3394c7d514ed94e87f7c61fa3",
- "dist/2021-09-08/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "5f92b4d12a9eaa50b29b81a3dff1959e59966f362b67c346b74403138fdb320d"
+ "dist/2021-10-22/cargo-beta-aarch64-apple-darwin.tar.gz": "b81ef641492ff2f03a93c8fbfbcfa78db2f6574d1998569d68dd2ba0e08ee186",
+ "dist/2021-10-22/cargo-beta-aarch64-apple-darwin.tar.xz": "925090782ad982202ca554a84e9d4a7b190f94b0b220c23e73235383d6ca367d",
+ "dist/2021-10-22/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "eba42edfebc85c744f4c6874337847748df65e430915f47238a93b1b7e96840a",
+ "dist/2021-10-22/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "fd04a8c4058ff287ea0256fd9f33a4b04b4f098d6911e8d827525cdeda6f169e",
+ "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "c7abbf1f265435cc9f6f0773d30321fc99353e0ddbf0004d00f47433eb3aaab1",
+ "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "3363dfdcd7106841edbd9029676ac339ff54c142921d71d92e308bee2ee33066",
+ "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "fbc5d5f70a36fc73f4d34d101aef4be78e38b5009ebf690fe46ba32eff6c1fce",
+ "dist/2021-10-22/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "220f23f50645532df4e5a4b1d6d894ce66a6ee2e5576fdf552081644a74a1c8f",
+ "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "94b42b8639ce541c1a355991f20d9934c72e766b6200d742d2d5b3b2f499f782",
+ "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "e32e9df3ab261fe20c363406d655fdaeeefc9dbb3d69da4551cdf9c22c418eb2",
+ "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "301c303ec0db0e342ecce4e259e79810e082766bac8f9907c353bdf490177863",
+ "dist/2021-10-22/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "d6f9409076ab4e2dac5ac5c07bac6be30e83e281df9efe2fa68386928e2e6faf",
+ "dist/2021-10-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "a4a82d48b2b1e6a49c0a765f9ee4d01e7ce4b0543128745d13cf4684c56eca8c",
+ "dist/2021-10-22/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c9ca524ba0e76d9fe38f0e4af337d14b97fd97dcd83d80ebf4725b5b03bea3ac",
+ "dist/2021-10-22/cargo-beta-i686-pc-windows-gnu.tar.gz": "973eabda91963d58a9cdd1491bcea15834874fbca018287fb7f5c8bdcdf323d1",
+ "dist/2021-10-22/cargo-beta-i686-pc-windows-gnu.tar.xz": "cbbc14d1ef0e4579167fce4a5fac43b22c87882049a3d0edfbace9fc5c103ad3",
+ "dist/2021-10-22/cargo-beta-i686-pc-windows-msvc.tar.gz": "ef090943f6c90bb3327225e0256e73762ca2f73ae5d0d07b2c828709077e1132",
+ "dist/2021-10-22/cargo-beta-i686-pc-windows-msvc.tar.xz": "42708683ba5ad855880ec69d92192bd9f99ebf102beaf6c53680cb8733fba9e7",
+ "dist/2021-10-22/cargo-beta-i686-unknown-linux-gnu.tar.gz": "b6c260ba19734482439bf6d12b8e87e82f269f1bec447ec85e59372ef6489eec",
+ "dist/2021-10-22/cargo-beta-i686-unknown-linux-gnu.tar.xz": "fb6036ff910d075fb5e483000af641328e6d7d01c33255c099ed1b0302239918",
+ "dist/2021-10-22/cargo-beta-mips-unknown-linux-gnu.tar.gz": "71e4e5fcf055251089ac0d37b5ad873eaee6aa0380438cd68f140a16d3a37cd1",
+ "dist/2021-10-22/cargo-beta-mips-unknown-linux-gnu.tar.xz": "b89acabf106b10c5c3421574bea83d8baf1f29d040c40d5522f85e2e6afa6373",
+ "dist/2021-10-22/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "f544ea08d2f6086dc49c4d635116f3b4b804e5b68251e5fad433d538ae5e8226",
+ "dist/2021-10-22/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "54b0cbb4292cc4733a704017775e5cd4a9be34d53a4c666d6fc556472b508e1c",
+ "dist/2021-10-22/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "5e81253ec483f096e23ed98f939220b029814c041b4b72b93e994cead3dc4f4c",
+ "dist/2021-10-22/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1a66beee5ccfd8b0fb4de52bccd11a0057248ac7fe8daf4f4d6fe0c0088044ea",
+ "dist/2021-10-22/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "2a6cc2e98ed575df64661595b6e1ec2814ed79fb63fe697c0201193eb52d70e0",
+ "dist/2021-10-22/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "ab3f70ea6977306c26c9cc368d64a116716f9ac6ad1a55eed23ddac894e7717b",
+ "dist/2021-10-22/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "ddd840c0c19077b4b45dc85920a2b2a37f176795b3d9390f1faccd44aa3d55e5",
+ "dist/2021-10-22/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "f5c9f1df082a7c48a63e786e5104d31e616c31d47514e9233b4a86d24700159c",
+ "dist/2021-10-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "4d39fac4d45dd73221b93b1d1351988ab4bf07ab04187a815467ab9b992f9490",
+ "dist/2021-10-22/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "3b6b0d38a3644028ca76347d5b82da6bac6e761a235516bf5b321d12ba909519",
+ "dist/2021-10-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0d5992a6e66207e4ead98d5bd627c181a052775f03ebdd2a0313574092a12abc",
+ "dist/2021-10-22/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "217940928d5c22553f910f3abf7b56bc832ddcd36282cb85c4b8142f9411147f",
+ "dist/2021-10-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "67ce7cb12cbd06e114a2f5dedd1d94c844f091ab05a764579dccf30e6158ea46",
+ "dist/2021-10-22/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "2cb17c66bdfcfeb567bb021c25c33a8c2b8df1366601d09fd9332278517a2f4c",
+ "dist/2021-10-22/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "e25a7fa310019a3457b317c9e3fe052602c82a25939c2ea8c012ff6016c622d9",
+ "dist/2021-10-22/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "1722ef69ea949c365f6b64735ee31dc92082db1177b94f0086b8aca790378398",
+ "dist/2021-10-22/cargo-beta-x86_64-apple-darwin.tar.gz": "f171fb45017640db15d437198b25758c49649b64338118501905f48ce957b93f",
+ "dist/2021-10-22/cargo-beta-x86_64-apple-darwin.tar.xz": "59c5f8ce9fa9dbf3e96dd8a38a52b8bff0ff0d97c081b1d343a654257df1e500",
+ "dist/2021-10-22/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "4f219f3661a03330b33d33cebadd5eac759968e1c4c3449f0f27433e715ab55e",
+ "dist/2021-10-22/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "5aed2d9631a2aa3fe016ae5e2ee312aa5357ce470c26c01171d14a159af7750c",
+ "dist/2021-10-22/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "c9dfb9c486cedac794cab6ac524805c10d2853c15416f3037ff4a5098514427a",
+ "dist/2021-10-22/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "a1e0aca8a32700e62fbc73b17dbb0be711db4e9caf535440b08bb1465d6a9c9c",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-freebsd.tar.gz": "61c041ba51632c029d916f274ed8ff92f1f7b23b5e9641591828e6251e205f6b",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-freebsd.tar.xz": "b61464e9e1c2e820a237f1f3d91cae8b0e62cda16dea51b32a8cf695b7a5707c",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-illumos.tar.gz": "1f9b7e500b22c34fa3080e4a15397a3a3827797c237d21459841055b5cb6cbaa",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-illumos.tar.xz": "97aba07cede4a9228ff1b937b8e884b23e9e246afe39b9d68896e6b4a346d972",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "c82bf6a11f468ba1d865a3cdc036b03f01e63a23272512583afa9dd9bbf95824",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "2efde3ef57e877f7a0aaba264ec14bc94d0cf3e4451b072c004c37e3f86288a9",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "17df9a194a8cd80871981fbde5fc333794e36a4ab219aafa7849ffeaf07d95c1",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "54fd84ff5bdf3221b151945ceacd71f51e71898927fe4b57887a0eba5d3e3676",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-netbsd.tar.gz": "0bd987dd970f98b297afbb7cf4906b1d2045ad09df929e8ebd291125e3c36126",
+ "dist/2021-10-22/cargo-beta-x86_64-unknown-netbsd.tar.xz": "054af5ef3148902a8fe07c2c445ea98a526f63203c13b849ba464d17145afe07",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-darwin.tar.gz": "2228315b5b7280a7ea9b3acfdfa1a8f0921391f67d792f32f53c1b303565a20b",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-darwin.tar.xz": "777d4c1c6bd3430771280dad79aaa16a6903901875529391e4779f0c2fadb0d8",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "1d2a74d8ff44feae6551613c182a87d078c0d4cc8f5117c6a3763f28d0af306e",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "67ab7519c7182a582fbd3e477b8bbbcba143a76e442cef94a47f0a03fa36ed05",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-ios.tar.gz": "2c2a8ca955cc99e86823bf7ede5492b04ea28c182a94d0f59b0d542f10128e88",
+ "dist/2021-10-22/rust-std-beta-aarch64-apple-ios.tar.xz": "bfd421654ad72aaff2610a104d0ea2afec579803ed16ac70ab594067cac292aa",
+ "dist/2021-10-22/rust-std-beta-aarch64-fuchsia.tar.gz": "b06020ac4aa9b5236d1888a59e2dc3519ac63c760ed0ef47b706466df437d5ba",
+ "dist/2021-10-22/rust-std-beta-aarch64-fuchsia.tar.xz": "92ffbe22d8fe9474aef42cd3bbe4808c4afa212a3f65f07828b39848dc03a1f9",
+ "dist/2021-10-22/rust-std-beta-aarch64-linux-android.tar.gz": "55aa7b2b3b79aba674bfc496efba37400086e192e6c7fa8483f5501ba31e68a8",
+ "dist/2021-10-22/rust-std-beta-aarch64-linux-android.tar.xz": "6219a156e46b7056a9046ab5a58af1a5386024b2961528a54fe6b1c3ec09a91f",
+ "dist/2021-10-22/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "f43fecdf75ac81f8b18ba5ec59625ce93b0debd27c0016edd76d5058e8182118",
+ "dist/2021-10-22/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "a032b56685b2b8431068565d652e5a174dbc9febe6de96945c037b96359d5cfe",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "bdb7d197cc36c774fe4d59a1c86b46325e93d82462c1cbe87e8ab415aba78e4c",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "061cb27b6d5b8e416457137334969733cd0727afe75d63d7954ccf547b7edc51",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "895d936a579c9642efcfdca400662264b8ba84ab9130f88e4dcd11c968a81e4d",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "29f3aa4005c64fa28f99af20221956ad21aff4a37c5cab9723959ddebb3c2b9d",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "b1e326b0ab30a2f9172a55272926cfa62dca9fbc2c590579f6c7685b8b4ad789",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "616fa68272334400c9110cf5a2cbd7d5c6e462cef8d2c5bc443c3ef6e9843e3b",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-none.tar.gz": "ec7d513787434a3cf2d523dcff7e37c28cff4b09b13be93c024729cbbbb5aa83",
+ "dist/2021-10-22/rust-std-beta-aarch64-unknown-none.tar.xz": "5a396cc0499690193879d10da333f5a3acc6586f1c216f751a1e62bf1a8b6618",
+ "dist/2021-10-22/rust-std-beta-arm-linux-androideabi.tar.gz": "f9baf9d74b094cabdab59c1eaaf5238caa175e7865c3497c34eba68be5b2d756",
+ "dist/2021-10-22/rust-std-beta-arm-linux-androideabi.tar.xz": "0c5f14f311e29233057ea466123ef9c33e3fffdc798358f0f339ce3869ffe9e4",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "e3c2ffd3d69ba9035048fad22103989ec97b892de955a94015e16578e42481e9",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "3e716d6aab270f764233f50a25a33d37a6d34c2dea23b3cd1aa5733c72c13958",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "65b74540b47fcf7fc8a88cbc5cfe54ad67c1060722c37af7e31bebe2b3c204ed",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "4bf4f75f7c4ed171ef7705764f71eb899763205a9a4727343b96cb209691a97c",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "be073a69a1e9de0f87511a5a8b3454b3a2d24319571c25f347f7213c872a54bf",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "57be5edb2c00745235dc486b4e6e6f0e6b40edf16481405abe3ac360190040e1",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "53c39c89d7b19e45e1a4f32b07eac8214a7d5d277a83e4a88d7ab8820bf2de86",
+ "dist/2021-10-22/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "b9f058907117e3f1921fb5ee73e04c6114154870067dc8791382f3099aeb5c0a",
+ "dist/2021-10-22/rust-std-beta-armebv7r-none-eabi.tar.gz": "bc3d93dd7381749a7d24eb904c7fa74aa6e2a575ad1af5ef7e34ffa07e91105e",
+ "dist/2021-10-22/rust-std-beta-armebv7r-none-eabi.tar.xz": "b605ced5cb597a2973417f4de55fb39cfe12b1209c4249ced9232091395d8e91",
+ "dist/2021-10-22/rust-std-beta-armebv7r-none-eabihf.tar.gz": "315432af4541ceabb14891da9ab6af6717bba88f1caaf216053f75405ff8997f",
+ "dist/2021-10-22/rust-std-beta-armebv7r-none-eabihf.tar.xz": "aa643ea7978ea7911e50ab65ba0af7bf018a4bf9ded1da8e161ee7ab13decbfa",
+ "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "3f780d36c780b1379fde18fbcd6a1f75efa766b56a4aa6933c9bb88dcd4f4ba8",
+ "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "d0c87b4127f10c85368254377013053747c10d2d7dafae2f5643a3526f938f48",
+ "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "fb4a610676f9102dd206a1762be6bf7838b3eb0fa08629df8199573246bfc38e",
+ "dist/2021-10-22/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "192d9bf1354737dc576bfdcc310c936e065039f39303370008dd0fe3d3e8ec65",
+ "dist/2021-10-22/rust-std-beta-armv7-linux-androideabi.tar.gz": "5dd746bb8db14ca9f968a651f3ae7e3c3c5a505800c0c3da8f6469809a81230a",
+ "dist/2021-10-22/rust-std-beta-armv7-linux-androideabi.tar.xz": "2cd651fad1f2820a2bb9b828faf292d3029ce633d24283d9a5363a726a024044",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "06f337db74903b607d09151f8a5178ce48e8b5905af407ae9b37445fe78aeed0",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "8851247487823bbee990937a1f83578d910985ed4055fe3bf339871a7aa28bce",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "5696a2c0fc2c3141d43f2d97d8e4959310032756cbdf0140dde28a5843b431e8",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "d8f9a3669d550f1c6f338d99ea74f4e48771620d4125bbd408cc750a70ee4686",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "326e4ac48ef1e1a60c434699b5fb09b9d0581e020bb745196011f2f61af41a13",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "cbd10db975412fe275d12b81cdfd5e97c0b464194639dcc439cd72a65790d601",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "977c9e94e25fa9a1db5f93ec800d529d80d874ceb2ed3a10bff63639fd24da59",
+ "dist/2021-10-22/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "0729470e2138e90d9140e30779d7397e58ebfc1ec243e55caf90ab12ef904da4",
+ "dist/2021-10-22/rust-std-beta-armv7a-none-eabi.tar.gz": "3115e3b7f0981dba799902b212f350608042a2beff3bc3b32e930e9c9c3cca17",
+ "dist/2021-10-22/rust-std-beta-armv7a-none-eabi.tar.xz": "75b3d8eba51877916129d8dec07bc86ec6e88076af79cc221e8543695e64da63",
+ "dist/2021-10-22/rust-std-beta-armv7r-none-eabi.tar.gz": "9787d23a7078c94b4ac33d34cdfb68da586d777f020a6284bb1540b54069f476",
+ "dist/2021-10-22/rust-std-beta-armv7r-none-eabi.tar.xz": "c8f9b933b2e9c955e6bbcb141082f6b5833f89f34de16e14f54e8d4aac02c473",
+ "dist/2021-10-22/rust-std-beta-armv7r-none-eabihf.tar.gz": "ce9ea3ade0886bf7ea40a1066981d172d915aff4c54ca325d72ed823c7e17787",
+ "dist/2021-10-22/rust-std-beta-armv7r-none-eabihf.tar.xz": "2d2442ed2ac017777d3fab1a3f69a578a9db1139fa1aa63dc87113071f08a6f8",
+ "dist/2021-10-22/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "98258ea791d398c6a29e1ebe28557aceb59ac228a0bb1332bdbd9f702c61a4bd",
+ "dist/2021-10-22/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "a4172c8c2b719d0391654968377fdba932343e444bc78482f19f731ca45806ca",
+ "dist/2021-10-22/rust-std-beta-i586-pc-windows-msvc.tar.gz": "2221360e32bdbbdbf073a4bc1fbbb98b86bd0a1df526cb8dd05dd521ea402c7a",
+ "dist/2021-10-22/rust-std-beta-i586-pc-windows-msvc.tar.xz": "03c53e31762e5ccc58d1296a8fcee123592dc6d3b88d0c81ed1f8305545faca1",
+ "dist/2021-10-22/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "612eb9bc2a06779ec05f6033f44b18f283d6cc8dccac0d5c81a6d09f515fc077",
+ "dist/2021-10-22/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "70ad4e52227ae069a9e99cf53e07470267abf1f2ae0398192ac854cfd31d50d9",
+ "dist/2021-10-22/rust-std-beta-i586-unknown-linux-musl.tar.gz": "8a5dd3dd62cb31c77aec2e00847812ba53e951fb284c74671cf3875b18a015eb",
+ "dist/2021-10-22/rust-std-beta-i586-unknown-linux-musl.tar.xz": "10650efcfda713c2a3053a9c505847dd021bed19b1e3af12d58742deb76cb421",
+ "dist/2021-10-22/rust-std-beta-i686-linux-android.tar.gz": "6fb4f4ac2b448bebade72ba2080bdcf579b6a40041b311301452ee41ea267ea1",
+ "dist/2021-10-22/rust-std-beta-i686-linux-android.tar.xz": "6e0e8feb477ad35bab1ef599f51f64b4720dc37194dd6354a7a4bfdbacbf2c82",
+ "dist/2021-10-22/rust-std-beta-i686-pc-windows-gnu.tar.gz": "0b0c0e86be0fb63dd56b419f0b8d05eb59841649120e16a8216bbe490a76db1c",
+ "dist/2021-10-22/rust-std-beta-i686-pc-windows-gnu.tar.xz": "c54a116404d31591d6a6a1a332e4bb8ee177ea7a0367b11eef6a8cae6c1c0325",
+ "dist/2021-10-22/rust-std-beta-i686-pc-windows-msvc.tar.gz": "14313eb7b20a3a3739a28406b1544cfe421c593a3198b081956a1a54387cd0b8",
+ "dist/2021-10-22/rust-std-beta-i686-pc-windows-msvc.tar.xz": "54fb4abc77fb6c97929641095ef86e559a4cb116cdac7dc4bf34a81aafa03681",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-freebsd.tar.gz": "9a2a5b2d3d5cd98cb3f9a43fc34d3dd0dcdf9bd104798380f70373440edaefa4",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-freebsd.tar.xz": "d0165b16890da11196a1e4cd6b48d545f44ddb996ba9515a919ecad85cddaceb",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "a42e125c252eed17664a50713d5e2f0c43f0f9ffe54e471500db75352d1e2147",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "705185a2b4b98f6ac16a9106af60f30618c24d6d93ffb0283a41cd31f992750e",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-linux-musl.tar.gz": "1a01712d4b8b470548c22a24e7e9524c0ddacfcf15459b490531e68e62b8a400",
+ "dist/2021-10-22/rust-std-beta-i686-unknown-linux-musl.tar.xz": "a86f8080ea25267f7e127f23bb75538cc3032091061b1fc3ce95c917d2a1cc92",
+ "dist/2021-10-22/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "d6d06becfaa6a4b0cb7131fbadd6cc6ff58edfa11fc6d98e69d2cf5388e8bdef",
+ "dist/2021-10-22/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "65bafaa34e506e8bab15d2442742fc075dab2ea8687c69f6090acf0204b6fb06",
+ "dist/2021-10-22/rust-std-beta-mips-unknown-linux-musl.tar.gz": "53a48c17c4ed3740049d0c88b14d2a1189e7ef5fa08a926c8ca26ec5b2b298b8",
+ "dist/2021-10-22/rust-std-beta-mips-unknown-linux-musl.tar.xz": "14525b83b69fc54d4c808ffb69e06f015850ea9186837c670dcc23b5bc66d4bd",
+ "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "1b8f11cb2ab076f00cd601c1465ff3a2e3857cdec255c8ecc1697efa713f5626",
+ "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "31e824a6243a6e15ea96a2984c69711e312eefa5214ba349ef6d6a4c42fffffa",
+ "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "89178cf43cfbffea696390c317230d39108e529803e28ca60d37b6167e589dbd",
+ "dist/2021-10-22/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "8b9fc0f9a2297d15abc86db95ac8768e872ec1acd21461e599a1aacb80f4b182",
+ "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "13ec0039303d3df358ccfa4fc19924df0ce17b31e8f57b13e7367db68bb9dfe8",
+ "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1266340a228c8cd657d0ee7ef257d80a33b193c4ecb742cdb82d469772311499",
+ "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "b100adc79e776116a267bc918ded30c4c8d27d83ed21f65f9428ed8831d101b6",
+ "dist/2021-10-22/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "6966af76ccf83f37657efc4aff88887de81642dddc3f2ef59dcaa91219d4f674",
+ "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "0b7a859f952741a740458609cd207d5f7291c054fc6d9a0191d3acf0f216bd17",
+ "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "2e6e61f68fc3772a6c3b3f0b3be6d99bca1a57b5f568e87397765cf6fe867dd1",
+ "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "881946b261399e50992beb3cc613ca2141736a7480103fa1fb117c1e7df2b1db",
+ "dist/2021-10-22/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "223a78a4c5055ca00a7d5b40491aef9498a204759cb388e734408e305999713b",
+ "dist/2021-10-22/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "76d81922eb6f61d33c10f2754ccc9b1394ae09feee5818b23b62f768f0e6a370",
+ "dist/2021-10-22/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "be57410669ba5a516dc935fd1eaa73b2d0d3d237a2eb184a8dadce919bf1975f",
+ "dist/2021-10-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "cebf48de57e57285c91092abc01ab1fd9bc7eb660eaad3db2ce71877bd6b9352",
+ "dist/2021-10-22/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "30a8fc47441c4f7b34f540f5132b3d7ff9756e8906ac6e2b9df5ea8fb622ad65",
+ "dist/2021-10-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "7deb058683792cd3fcab92b950f653a4ba0d2a2997bef508c6d1d04be319f057",
+ "dist/2021-10-22/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "c5d26bbe5b6c64ce9cae78465d22faa98ef956dc4d8bacc91a127a7f439f7b11",
+ "dist/2021-10-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "bf06959a991270e9e15d538e70d078a5241b6e87d62a55a655e4c2f9e8ea2964",
+ "dist/2021-10-22/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d85b330532cb6743071ffa117fbe8bc26b9c6167a0ff76c0ba32fb17c0247c70",
+ "dist/2021-10-22/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "7dda5e010ddb4afd6e6efeb9f43ef17cb30af7ed9f172b59e6c737b2f9d66ef8",
+ "dist/2021-10-22/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "35d8feb28897bead99c17d952b711888f2f6f613fef767f28e3593fb4aa2dc36",
+ "dist/2021-10-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "2e7067692c10447d50df8e9871f95b4ea925a88c5792f973b3c51325afaa8457",
+ "dist/2021-10-22/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "4b2d3bc61727c87f7c2ba129e9147621c3e3efd542feba3acb6596ea91d10d71",
+ "dist/2021-10-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "093aa10e425beef7d66e9986b045543b3dc04c296fa3b3fdd9071fd6d61b269b",
+ "dist/2021-10-22/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "8f3512c368b7c44c7d8ec9e1dbdbaed344859ebe2d0dcee22118397d41b841b3",
+ "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "adab0b58b93d37949eb35d4a6f3ba9e6b43630e4a82f1d9047116f1462cd1809",
+ "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "6a0410d1194ec0c471e384c5d02aba555efbd47b36a3544c56674fc2080c51e7",
+ "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "19c8be8430ab59b92006e0bccf186687569ca172b54f934ff4763da20cebdb58",
+ "dist/2021-10-22/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "6cb9647a504683fa5c67e5ab2e737bf1d6004dd4a7ffbaf593dea0f9844ced6f",
+ "dist/2021-10-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "cc2d94e753035ff0b49490173b042d21f1ea58711f7c6ce5cfdfd79a76e539b1",
+ "dist/2021-10-22/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "de398391e577f2fa09f369fbea4114c6cc0f1412884c6f52c97d71c74920462b",
+ "dist/2021-10-22/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "feefd67b9c9dceee7ef7947753ebd990a914d7a54562b718e6704d35a1f5c75f",
+ "dist/2021-10-22/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1b550a911a51514f8d69b9b763cc3379cd674615090652a253eeb7b585d2d97d",
+ "dist/2021-10-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "4d7d78589d6d72e5ce60d6997394c4d7ff03fd2bae471ef3334f1d5bff9f18d7",
+ "dist/2021-10-22/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "ec499330b2f63047eb43bf98b1e66d301d7ea7015447c83307ab528421387502",
+ "dist/2021-10-22/rust-std-beta-sparcv9-sun-solaris.tar.gz": "7e48f11954d44dade640c86cc87d5841ebd708643cd5220ae7d07127f71ff333",
+ "dist/2021-10-22/rust-std-beta-sparcv9-sun-solaris.tar.xz": "5038770dbb2dda71d32c4270653fd3ece96062b24ad55dc8def6475e464210df",
+ "dist/2021-10-22/rust-std-beta-thumbv6m-none-eabi.tar.gz": "b8b9a59bf1a9127b26aff54dde3a1da9992a99fd3d601be7cc1daa6ce3c7b6e4",
+ "dist/2021-10-22/rust-std-beta-thumbv6m-none-eabi.tar.xz": "e0a96a8b105466a3279da3d9bf589724def7326448bc6f51ae6f8e8aee2ac880",
+ "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabi.tar.gz": "cc3a8d935ae2101cff8af86fb066c09672f9fd0297cd9d6b960c9f4877618e98",
+ "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabi.tar.xz": "9bafbfbcb01e23f58b1adc7fab26e8ebd135c5c20589887278065f75cb5b5350",
+ "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "8dd7c2cbc2c24e5220ff6a7f5caffcca6605f3d76ff66f766af00ba4bb316067",
+ "dist/2021-10-22/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "963a698d49c8742ec5c7520fdefa1668db573eb01bd7774f80133496122b0517",
+ "dist/2021-10-22/rust-std-beta-thumbv7m-none-eabi.tar.gz": "3a01a35a10f0efe48cef64d45e80fccab31df8287f500bf280b5d9bd5784ea3a",
+ "dist/2021-10-22/rust-std-beta-thumbv7m-none-eabi.tar.xz": "84a5b9d9cc21a13cf1e2e1c29e7af63c75690cbb2293c63fe95e075ebf59815d",
+ "dist/2021-10-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "946e96f404b8a9f4c8139e90172ea26f3a6c509effc6e1ff16a49dc9ff6cc1e4",
+ "dist/2021-10-22/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "787cd874aeb33e4a4fed2726a571d39f6687da20625aa9a485a95d7167b321b5",
+ "dist/2021-10-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "70fd17c069fe4b6a318d887794c54a142275cc65f088a7bcbda5bbbd7c9d6aa7",
+ "dist/2021-10-22/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "15ce829bd9ea0a1ee918e7887392ce1e74e00b23509b802f5f45550176d78768",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "2edc66ee89c319ef7c9520c5203185a5b5203ca4ea9996e0142075273ccf84b6",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "3c129a2557639fad501c7f1474f45535a55c33813a889f08521f4a7d527010ab",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "354e644c51ad5863bb0eea09e0c5d1aa32858e7025c039d693e2e433e1c18c04",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "6996a329a81624537d45b2401b8dba81911e5c61d2fff6bcd63c5fb15b2fbec3",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "97d6aa47e209650860e97d442f7ec5c5da385399aa5f06bca4c7f9a08767026d",
+ "dist/2021-10-22/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "dac5cadd67e5d162e00861ec5d2c96166fe1a80954237068aed6072afe0f728e",
+ "dist/2021-10-22/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "e0161120cb6cefb23514c839eb2be13a54139d4f408563bd9dc1d6b9d665496a",
+ "dist/2021-10-22/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "94bcd63f3712cb3b09948ed62c8db889e2bc78b97d868c89386f912d0daa1b4d",
+ "dist/2021-10-22/rust-std-beta-wasm32-unknown-unknown.tar.gz": "00a37ebbf36bd66ab6e0b957e93c7a2e5c2d8567583c65873abc1c79b37bbabf",
+ "dist/2021-10-22/rust-std-beta-wasm32-unknown-unknown.tar.xz": "75589caa1835ee12362a2ad581828c9faf0d527f48d5a07c1d7f0b810e035def",
+ "dist/2021-10-22/rust-std-beta-wasm32-wasi.tar.gz": "2276b9ef2ff2faa665f15d3572abe0d13a5bb9ec0ad08a6a0c00d9e143464993",
+ "dist/2021-10-22/rust-std-beta-wasm32-wasi.tar.xz": "fa132a08849d7c583dbf37db97f3702c263b17de595823d87fa14e56ff21ef3c",
+ "dist/2021-10-22/rust-std-beta-x86_64-apple-darwin.tar.gz": "47454a419e6a87b057047c002932cd2f0f52a77ed4c3b4e4d9b65cc4f4ddaaf4",
+ "dist/2021-10-22/rust-std-beta-x86_64-apple-darwin.tar.xz": "f9040fa310d122651461d026f43873aa18d5f2c63a9f3bdd47f9a034e4153348",
+ "dist/2021-10-22/rust-std-beta-x86_64-apple-ios.tar.gz": "e143c4c8d394810c7734824476dbbfb2a73b3b62cb8a708f796e0c0332deede9",
+ "dist/2021-10-22/rust-std-beta-x86_64-apple-ios.tar.xz": "53c660ef68e1898574f62725c2f50fc2f26539143c0be0675327a33511142f8f",
+ "dist/2021-10-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "e419db2f8f12467335c8571902f1ed163a5407394914f55416fe948525140ec5",
+ "dist/2021-10-22/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "efd2b6df7dd439b0ae0312831afd4517cf19adf619916eeda1f571daf1dae723",
+ "dist/2021-10-22/rust-std-beta-x86_64-fuchsia.tar.gz": "e669378ed5da5948dbe232323ef3926f37ad430feb8c398259229fd18675de20",
+ "dist/2021-10-22/rust-std-beta-x86_64-fuchsia.tar.xz": "5a26a35164ae44467d256e6fab0e8f45731e8840204635ac9b1dd1d7d8f96810",
+ "dist/2021-10-22/rust-std-beta-x86_64-linux-android.tar.gz": "0d922ff7d7658c296246c22f4440a8975c8036f7159508e2fa964d1f2ad3aebb",
+ "dist/2021-10-22/rust-std-beta-x86_64-linux-android.tar.xz": "d775ecb6054216f0f48dbd0acb7710fc097ef6d61df9c1f59139721ada7bef8a",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-solaris.tar.gz": "1e830dc490e9b00b86c9d55c974feefdd87efc06c1bb90088b41737151987dce",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-solaris.tar.xz": "cb37a89a871d61849f9aa262bee7248813a8c7a422872aa3926f20c1adf4ec63",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "d83a17c374e937b9a06a364d0be980f4dc953df01efccdb3a0bf853ffd889718",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "94fb51d1db6482adf683b9953fcc942923fa5c85cbb63f7b05ad19c24272a21e",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "4b7cc0a0a6b07054bb1da0b75d5f687fb38653a7b31f7610f5a90a402839e481",
+ "dist/2021-10-22/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "267f634ec4e08d0a76a75ec0f4ae037aaba44db3ac2969ed3f34d74db43bea1a",
+ "dist/2021-10-22/rust-std-beta-x86_64-sun-solaris.tar.gz": "3648f1129895e89467a569219570061a6c50937d87bbb407e6b3b6b1f488bac3",
+ "dist/2021-10-22/rust-std-beta-x86_64-sun-solaris.tar.xz": "3a7d686102d9f2469e180a80679db52b6c8dc8ca35adf3e50a25b7bd35f4c6a5",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "6cb296c0d9e07e00b8561c2f39a7dad9c9d74e224658fa9a7039e34d4b5f3aa7",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "9e951fec5ee4a4a655693d1c9e205413aeb3120a7b2c0bb6673f4392cdf9fa6d",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-illumos.tar.gz": "35b6775e13b79b946398a65d6cd4f15d26e160dbf44718cf177679964b2f3cec",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-illumos.tar.xz": "84d127ce90d62f1698a948ffb247cba400bd162b9864d2ca7c0240a46b23c88b",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "53a627ff89fbfd2abe9b4354e25e02d2ae8d05fcf6f6cefe99b84aec9775acd0",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "7692b0b44eea139874fb8c6cbaca46b8f156ce392454ee4891daad532a5c6baa",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "853db076a2c469e37003fc8e52af2d0a2e31cd7f74c51147f00b04532df5721e",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "6925429b5f25d0454abbd68ee333623ccec9d706fe0ec528fb619b2688528770",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "13e920a779485d04952e4c402b42fac9b7570098e5e32394996cd985889682fc",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "158062a56de043afc4acefc8eafaa536c3018cbdc7696b6d909c757050062b42",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "1701a13827b3ab22fe78569704d39a2f699f463b2f6f159407a39eaf4c7fd6d8",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "f10ff1def90cb101179f11b4b07ceeec0ae26ee15c7a85f80e4e31c61baf846c",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-redox.tar.gz": "20c6c718322cc341f0e1f69a9dc42f3146d10f32075d32376a241a90a2e40f48",
+ "dist/2021-10-22/rust-std-beta-x86_64-unknown-redox.tar.xz": "d0429de3b0391f063836c765ad17e2fd1940f737b69961f501eb9d2573cba6e5",
+ "dist/2021-10-22/rustc-beta-aarch64-apple-darwin.tar.gz": "31d16857f6fec033e6f79121040eb025c28a1d049014c6047fbf1057450f86d6",
+ "dist/2021-10-22/rustc-beta-aarch64-apple-darwin.tar.xz": "997a9aa6db5e23f476aefd3f4799f986a51fda3e31e2b293309fb65fa92b0370",
+ "dist/2021-10-22/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "73fb943292d50a372f2df490e47235f395ff7eceac353be74fde3adcf45d363f",
+ "dist/2021-10-22/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "30a4a4cbe3fb683b8e846052a83a3185d1b8d714251bd6ad0bfc251b49a72121",
+ "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "b238cffde0b9ae2305e501970cb9cff1782331f1cccbf8dff84979d1ffdf0625",
+ "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "5d01b8e471419036703886fc7dcceb89ffc88fa62994727109865339fbe0c92c",
+ "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "8b8b48fc67a2093502baf21c372870bad42840377548e250023c9f83884322b5",
+ "dist/2021-10-22/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "a9e73e67a7120968474040dbde7b12668bd6e3a6b4f9d91b8c9a66474f68e40b",
+ "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "4e83419922b4f02b1c1c62ca14db65863f4226cbaa61674ac792e860c026a948",
+ "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "20d7369422ebb89f8e1064616a9842cbc98d9056910a2d0ba46f8bcf144cb794",
+ "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "05ab3071cdb3ea4e39f53e179c754d2cf64800ca1c38ff887e45f60294d6e222",
+ "dist/2021-10-22/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "e8509c60955ecf4938575a7a40091ba5d7aff77c9c3e24208623882d1bb45e6f",
+ "dist/2021-10-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "185a3e399dcc67d8fb43a0174ef8e15c36a068b82aa33db8b42c948c2ee15689",
+ "dist/2021-10-22/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "69be7881ba1b2d4348ea06fc2d31a62fe484843e660f399349c49a17852cfaa7",
+ "dist/2021-10-22/rustc-beta-i686-pc-windows-gnu.tar.gz": "74c3a25a67b10abbefadf63bc09f6069242267a9ca8a9177e2f46e2b29869b75",
+ "dist/2021-10-22/rustc-beta-i686-pc-windows-gnu.tar.xz": "9f0d3ce0a00b33bb591d6b615f9cc80a714f3ea0d787f410da7d643ac5e1144a",
+ "dist/2021-10-22/rustc-beta-i686-pc-windows-msvc.tar.gz": "feac518beb813b2d553d6ee1ce03daf890c956918f0de69d5f59d4067f2f60d3",
+ "dist/2021-10-22/rustc-beta-i686-pc-windows-msvc.tar.xz": "aad640ae5e48f489148e1edf5e815a78b19288d916615e2af8805f0023e15686",
+ "dist/2021-10-22/rustc-beta-i686-unknown-linux-gnu.tar.gz": "c5996c458e6e1a3f3dbcb70debe562bb5d0f4a6eadd97932d8935209fbbe6809",
+ "dist/2021-10-22/rustc-beta-i686-unknown-linux-gnu.tar.xz": "d5ed640d08bcf3770b80386282c442d79af38e4c7e73be9617d0ac72d553c507",
+ "dist/2021-10-22/rustc-beta-mips-unknown-linux-gnu.tar.gz": "aa0dd3e77f92c1cc21f550c59761a437d3a8ddf31b23040e8849dd116e209835",
+ "dist/2021-10-22/rustc-beta-mips-unknown-linux-gnu.tar.xz": "3c7bfcd663507730ad3d07024e1d884dee6adb49343bef0cfb8fd07b8a56c6e4",
+ "dist/2021-10-22/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "0370337cce565e6e363e6de59aaa8c2e17db49d79496086c20f00d80198635c8",
+ "dist/2021-10-22/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "30413f65a4fcafbbb6a5302cc65bc35edc549cded8ce6a32277ae9a499adfe59",
+ "dist/2021-10-22/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "0e6ee26e237a185a26068c2c69ef095ff37f24af7984bad91196ad253dae196b",
+ "dist/2021-10-22/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "f0185e074bb0c6811d244502ce93384cd7256840fbf64025e074d97e4ccb03a9",
+ "dist/2021-10-22/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "a2c1f733c16d62300adef3ed41f9c5926f704e6b3d47e98cc615665496aa4f17",
+ "dist/2021-10-22/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "3945ad08c0b296a700bfca778994fd93bd3cbe643517ba20a60aa1f9a88eb2cf",
+ "dist/2021-10-22/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "e3871e21ac938b4bf3a1ed44fed2f05fa3a27d3eb000d98876f9f220a5fe9175",
+ "dist/2021-10-22/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "bdc7cddaf0031af1b737fd0c2510ef018d68ebed914200ae8acbfd31ad38ad06",
+ "dist/2021-10-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "9ea42f7e50864bb514293461d3622096fd7a73e8f487578ba1425a3e8d26a970",
+ "dist/2021-10-22/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "c39cf38c563b16d303bc2cde8c67527e7d2a74e8c5375af73744d9a9e3dc5e1e",
+ "dist/2021-10-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "dee289bd99b3b573493160446f923fb2f2b66926a5a69c0a7704eb2aaaac3ea8",
+ "dist/2021-10-22/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "e3c89f1baa358b6a28ae567981d5efd457d2df61f2eeee19bceeac715793510b",
+ "dist/2021-10-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "748df03717e997a01a6d222bdb6d6c0b1e206d9be55b74c14c3374a333ad8d55",
+ "dist/2021-10-22/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "5cbef13c038d0fe822920eabf91c152a7130e50824fd203e3fffff4a44b10bcc",
+ "dist/2021-10-22/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "dd0ec4dba66712a10c3ee5e5ef1835210d8632766c17a4afa1ba0594b6fdd35c",
+ "dist/2021-10-22/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "30d736ad6f32019435613fec04b4474795c8915e878a528c46de453a25df1bd9",
+ "dist/2021-10-22/rustc-beta-x86_64-apple-darwin.tar.gz": "14c1ba057a56a0c34f129ebae29c6a9453faa03125f1fe88b564355c186d42bb",
+ "dist/2021-10-22/rustc-beta-x86_64-apple-darwin.tar.xz": "67d1c23c910e038c6238d286af0141f0a954799dc12a6b935d47239f4d2e8bd9",
+ "dist/2021-10-22/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "7685e5b408bf70aa4c8af5ce7b5e5d5a6ac7125c75e7b10a9b3dc0e2dbd4cca1",
+ "dist/2021-10-22/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "a52b846d34cfaeddb57d00d0209b1829fb129049ef61212937c0f19fff5efc91",
+ "dist/2021-10-22/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "a5c2dce3211ec671959abb8b2f7fc34b572e3bd44362c61b98e0850c0530d1bb",
+ "dist/2021-10-22/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "ba948c4a665c349732de9f8faddc2f7e0f7be5995ad88af44f8f4f5ffd4b9387",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-freebsd.tar.gz": "edf7d1c9c9288cca973a0bc3a90bf005d25df324c592b0b8d051f0de98b85f78",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-freebsd.tar.xz": "0c01b34ed39016866e945e0f01de830a68c54f7eef2ac83c3ab85318b01debb0",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-illumos.tar.gz": "6ddf6e92653ab0c00ec524e1274be3e644868cfa867933bc383e8e3e7674945f",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-illumos.tar.xz": "14353a439a306d0803d89a3ce3da5e5c91b9236ed84759fecf8b38ebe1d8a8b1",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "4d7feace1b414919ba2e682c748e24b31d811d7b54d710a7cf70e0b3c9c1a591",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "35593657a752a66f3052752c67c380e7ebace191a0be78c5def2cc3c1fb3a18a",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "04e752df5371b5d3879c8514b7dab27bcb35a7b8c7eaec0ec6e3ec5f51ff84a2",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "b0ef02ff310386b80a9b6113a6e44a437ab78b42480b4d0a86e828d97d92a3dc",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-netbsd.tar.gz": "387040cfbb92e6b2acc52067ab2184313de2588a6af65c0af003432bc9e69c75",
+ "dist/2021-10-22/rustc-beta-x86_64-unknown-netbsd.tar.xz": "a617e0ee647908038bd1b3f233b99db1a82b0f32875c9093cb66387f3b2bf430",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "5ef7d34a33925b7af081f2e135a0fd20ebb18f711372d432a570f8983243c93b",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "6003e9f8fb4b2a581e359e2e4f1bad83b9055d5a0c60fa0b752ef1aa15957f28",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "838f7773a9aaec82c4323d8412a441eb3db94da8384bc1a4a50969c5beea9aa8",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "403a2141367854a281302f9cdcc2d1b37a2415e8aca4cd5e5308af5fa254601d",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "6a3b69c8352c8262a37ba0104043a66bc579fb033166434a1b9eeaf115d8d1c2",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "f272195798b40df211b1d2e817e91bba68a1083026159cab4414ecc88ddb06f3",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "5ec04606fc7196f9a5cd130dc4c98e8df58994278ab50f7ea6baf2cdca957b07",
+ "dist/2021-10-23/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "a24513ffce8f76fa3334932268aed073958f904b1988d337df7bd4277d3a139b",
+ "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "8f078b404db9fabd8b0a45deb5110fab32e2ffe5f604f74ef787d9baf3f857ad",
+ "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "3569e3ed42cd9b4dd6f8b2838329c7864c6d3f7a5242cbdbcd9a756e6f2ca5ea",
+ "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "afa42b42631320a68d6a99902fd48b1e72d2daeb07a5be34b833f22ba6dcb67a",
+ "dist/2021-10-23/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "839a8576012332bb2ad01d5b4ab24d46af8644e38b3019b36c0ba5a9417bfd07",
+ "dist/2021-10-23/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "aa59c2ebf3bbff46b6c09aa1e7784ebf83dccd6df60e1295935ff3cc954fa755",
+ "dist/2021-10-23/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "e7f479891368cebb99f41b59508a3904321d600e20cc2507954f78386a448601",
+ "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "a971a861cc76d0a2a4c5fecfc4537c8e1c14f4d43013bceeed395722e8620cbd",
+ "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "5879a7a9af9c6ef6397f75e4b062527fee5006d655fac5b7538915b176d9faa8",
+ "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "dc66ac568c709f4b580b46d567bf2d79481566688e0ae55df1edd2a5f07fe0a9",
+ "dist/2021-10-23/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "a2ea4554d52b1181c589eefdf67c60bc0831f2e26430bd6e5e7bb4094db5dfc5",
+ "dist/2021-10-23/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "8d9ef4755d32e8dc480db1b130943f47b45cc2ba69b1e9fa3dfa128d63780b70",
+ "dist/2021-10-23/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "3cac0853da192779f4edc5bc3c913e4b93a02ae98b883cfe2717cc58329d7469",
+ "dist/2021-10-23/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "14c5197f4884f418a392bccce9ac3c9a09dcd0a710a337bba5959f5570c41e98",
+ "dist/2021-10-23/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "f9b14921e3a6bd006479a01579e6601787082ecc0ec8e631b8cea6a4f1c0b967",
+ "dist/2021-10-23/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "9f4efc8229a5a8561bea614a3df0da49349dc4118d72905ecd6feb6b6e1eba9f",
+ "dist/2021-10-23/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "02d829ac6d9013f7268e505aa2b0aa99db7e25ddc3d6555ca8f9a4c5ed3f01e7",
+ "dist/2021-10-23/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "8192413e5e376bf957a2caffe8ab15b3c235c714f8214a0f3a46711a79fe33c5",
+ "dist/2021-10-23/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "be155309daae3cb39dbbc874b2ddaebd1ad303b09f40e130ea8429cc7c9c366f",
+ "dist/2021-10-23/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "318c3e8235913f64c9e90b0e7c1fb50229caf59c02f0ddc702cf0728d54dc41c",
+ "dist/2021-10-23/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "50bf71e32ae2228142ad88d67e794ab00b632147fb554ebbfcda7ec79304ae2f",
+ "dist/2021-10-23/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "80f5b76c38d7300c5aa6a71a8b3325b28290b1bb936dd59287fa87d6dee044da",
+ "dist/2021-10-23/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "30a71791c6ed0cf3e0fb955fa697549dcd13d2c0f3e357d9723fa729c3a03698",
+ "dist/2021-10-23/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "7e5dc3dc89cb21638b452eb9b5c9f008803ee5845c973f2547f59db01b7a0100",
+ "dist/2021-10-23/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "e1a949b29d249361b306af38bba7118aa1931c14061b6fa7621027e9994b519f",
+ "dist/2021-10-23/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "ae4186e4faebc9ad8a13f06a97f96c48cbb35353ad649e25f2e80e519a9d272a",
+ "dist/2021-10-23/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "ca4466d872bb050cabce20ae04eb915ac3e39e4788899db7bec5b51ed7d5b579",
+ "dist/2021-10-23/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "0f39f27e2ee437df69975578c6e32b6e293bf3129f7e63bde83091330aaa496c",
+ "dist/2021-10-23/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "55700dff4b4f3f7d9dfee3317d984afe2b44681deb7b074441b41cfd59e497ed",
+ "dist/2021-10-23/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "6273db29aa2715ffe38593802c520adafcbb2300ed2595121bff628686eae675",
+ "dist/2021-10-23/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "7a4ce848a1083c16bc17bd22345427ba4c920cb887e90d612a8c3d1ddcf802ed",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "12a715fca796c192514157b43b0296d688cc46e9d81416a67a0019184c1703d4",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "9a651e94a0cdddef7c7a56e356e25d0f35d0c592b6a54f2cbeeb3364fc5d457c",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "2ea52a8413a43a10165322135064692faee0d03a453c4b28ddea480b153de5c8",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "843b06b9b21c56fe1749e8a5bda908dcc2b6d8206faabd04d050ce83f8c32b73",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "69210991cca5a07c0421254a2e18a29de28ab5019b490a576f7bb94496ca10b8",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "3f5a59ba68e004c06cb07ce83d4a567b77179e11071a8b5b8ab6fe3a70bdb872",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "7225fde4655ed5b4479ff9f4e61237a16280541f44aa751c5a06d5916e8fde3f",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "e844e80d99418bea9e7cf96cd389056d17f3be60e9412983d91c64e107a28b92",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "6c1b031bc408349c5d15bf494881dd75aa68df8e7417e6c72c061c7d3270cdf8",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "d24b970a15dfd41cb1b0027a4a5822e8c2b0217dd1984503d60a85fc6acf7414",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "5b5aec4bfde07863d2d5bb71f38d3459db0659df75f53567be6fbaacec33c7b3",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "851b9582bd2518a3e050127c46e59f7bb6b24d354c6e89a9b0fe4d3e09cfbbb9",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "758a05277e99d00e21ff9d8abf96a6da71350664a1eb85adbb1ad4cfa1934255",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "6431dabc8ef72ca252b257683fd2f5ce3c1347b18ff1d4b7ee7758c6906ba2af",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "51bdea94714c0892ca7020ddcc7c55bb20ac69eaf5152a38f83925d793b90eb1",
+ "dist/2021-10-23/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "660a23d1430164b01b3e1e8b50233be07fa0988d90e9880bb9044fe661537cde"
}
}
// compile-flags: --target aarch64-unknown-linux-gnu
// needs-llvm-components: aarch64
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
// compile-flags: -C target-feature=+neon
// needs-llvm-components: arm
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
// compile-flags: --target bpfel-unknown-none -C target_feature=+alu32
// needs-llvm-components: bpf
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
// assembly-output: emit-asm
// compile-flags: -C llvm-args=--x86-asm-syntax=intel
-#![feature(asm, global_asm)]
+#![feature(global_asm, asm_const)]
#![crate_type = "rlib"]
// CHECK: mov eax, eax
// compile-flags: --target hexagon-unknown-linux-musl
// needs-llvm-components: hexagon
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
//[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
//[mips64] needs-llvm-components: mips
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
// compile-flags: --crate-type cdylib
// needs-llvm-components: nvptx
-#![feature(no_core, lang_items, rustc_attrs)]
+#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch)]
#![no_core]
#[rustc_builtin_macro]
//[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
//[powerpc64] needs-llvm-components: powerpc
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
//[riscv32] needs-llvm-components: riscv
// compile-flags: -C target-feature=+d
-#![feature(no_core, lang_items, rustc_attrs)]
+#![feature(no_core, lang_items, rustc_attrs, asm_sym)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register)]
//[s390x] compile-flags: --target s390x-unknown-linux-gnu
//[s390x] needs-llvm-components: systemz
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
// compile-flags: --crate-type cdylib
// needs-llvm-components: webassembly
-#![feature(no_core, lang_items, rustc_attrs)]
+#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch)]
#![no_core]
#[rustc_builtin_macro]
// compile-flags: -C llvm-args=--x86-asm-syntax=intel
// compile-flags: -C target-feature=+avx512bw
-#![feature(no_core, lang_items, rustc_attrs, repr_simd)]
+#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)]
#![crate_type = "rlib"]
#![no_core]
#![allow(asm_sub_register, non_camel_case_types)]
--- /dev/null
+// compile-flags:-Zprint-mono-items=lazy
+
+// rust-lang/rust#90405
+// Ensure implicit panic calls are collected
+
+#![feature(lang_items)]
+#![feature(no_core)]
+#![crate_type = "lib"]
+#![no_core]
+#![no_std]
+
+#[lang = "panic_location"]
+struct Location<'a> {
+ _file: &'a str,
+ _line: u32,
+ _col: u32,
+}
+
+#[lang = "panic"]
+#[inline]
+#[track_caller]
+fn panic(_: &'static str) -> ! {
+ loop {}
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+#[lang = "freeze"]
+trait Freeze {}
+
+impl Copy for i32 {}
+
+#[lang = "div"]
+trait Div<Rhs = Self> {
+ type Output;
+ fn div(self, rhs: Rhs) -> Self::Output;
+}
+
+impl Div for i32 {
+ type Output = i32;
+ fn div(self, rhs: i32) -> i32 {
+ self / rhs
+ }
+}
+
+#[allow(unconditional_panic)]
+pub fn foo() {
+ // This implicitly generates a panic call.
+ let _ = 1 / 0;
+}
+
+//~ MONO_ITEM fn foo
+//~ MONO_ITEM fn <i32 as Div>::div
+//~ MONO_ITEM fn panic
//[powerpc64le] needs-llvm-components: powerpc
#![crate_type = "rlib"]
-#![feature(no_core, rustc_attrs, lang_items)]
+#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
#![no_core]
#[lang = "sized"]
--- /dev/null
+// Verifies that "CFI Canonical Jump Tables" module flag is added.
+//
+// ignore-windows
+// needs-sanitizer-cfi
+// only-aarch64
+// only-x86_64
+// compile-flags: -Clto -Zsanitizer=cfi
+
+#![crate_type="lib"]
+
+pub fn foo() {
+}
+
+// CHECK: !{{[0-9]+}} = !{i32 2, !"CFI Canonical Jump Tables", i32 1}
--- /dev/null
+// Verifies that pointer type membership tests for indirect calls are emitted.
+//
+// ignore-windows
+// needs-sanitizer-cfi
+// only-aarch64
+// only-x86_64
+// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi
+
+#![crate_type="lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+ // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}}
+ // CHECK: start:
+ // CHECK-NEXT: %0 = bitcast i32 (i32)* %f to i8*
+ // CHECK-NEXT: %1 = call i1 @llvm.type.test(i8* %0, metadata !"{{[[:print:]]+}}")
+ // CHECK-NEXT: br i1 %1, label %type_test.pass, label %type_test.fail
+ // CHECK: type_test.pass:
+ // CHECK-NEXT: %2 = call i32 %f(i32 %arg)
+ // CHECK-NEXT: br label %bb1
+ // CHECK: type_test.fail:
+ // CHECK-NEXT: call void @llvm.trap()
+ // CHECK-NEXT: unreachable
+ f(arg)
+}
--- /dev/null
+// Verifies that type metadata for functions are emitted.
+//
+// ignore-windows
+// needs-sanitizer-cfi
+// only-aarch64
+// only-x86_64
+// compile-flags: -Clto -Cno-prepopulate-passes -Zsanitizer=cfi
+
+#![crate_type="lib"]
+
+pub fn foo(f: fn(i32) -> i32, arg: i32) -> i32 {
+ // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}}
+ // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid1")
+ f(arg)
+}
+
+pub fn bar(f: fn(i32, i32) -> i32, arg1: i32, arg2: i32) -> i32 {
+ // CHECK-LABEL: define{{.*}}bar{{.*}}!type !{{[0-9]+}}
+ // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid2")
+ f(arg1, arg2)
+}
+
+pub fn baz(f: fn(i32, i32, i32) -> i32, arg1: i32, arg2: i32, arg3: i32) -> i32 {
+ // CHECK-LABEL: define{{.*}}baz{{.*}}!type !{{[0-9]+}}
+ // CHECK: %1 = call i1 @llvm.type.test(i8* %0, metadata !"typeid3")
+ f(arg1, arg2, arg3)
+}
+
+// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid2"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid3"}
+// CHECK: !{{[0-9]+}} = !{i64 0, !"typeid4"}
-// EMIT_MIR issue_78192.f.InstCombine.diff
+// compile-flags: -Zmir-opt-level=1 -Zinline-mir
pub fn f<T>(a: &T) -> *const T {
let b: &*const T = &(a as *const T);
*b
fn main() {
f(&2);
}
+
+// EMIT_MIR issue_78192.f.InstCombine.diff
{
::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"],
&match () {
- () => [],
+ _args => [],
}));
};
}
as
())
{
- ()
+ _args
=>
([]
as
// are caught by catch_unwind. Also tests that Rust panics can unwind through
// C++ code.
-// For linking libstdc++ on MinGW
-#![cfg_attr(all(windows, target_env = "gnu"), feature(static_nobundle))]
#![feature(c_unwind)]
use std::panic::{catch_unwind, AssertUnwindSafe};
all:
touch $(TMPDIR)/lib.rmeta
$(AR) crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/lib.rmeta
- $(RUSTC) foo.rs 2>&1 | $(CGREP) "can't find crate for"
+ $(RUSTC) foo.rs 2>&1 | $(CGREP) "found invalid metadata"
use rustc_interface::interface::Compiler;
use rustc_interface::{Config, Queries};
use rustc_middle::ty::query::query_values::mir_borrowck;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::Session;
use std::cell::RefCell;
}
}
-fn override_queries(_session: &Session, local: &mut Providers, external: &mut Providers) {
+fn override_queries(_session: &Session, local: &mut Providers, _external: &mut ExternProviders) {
local.mir_borrowck = mir_borrowck;
- external.mir_borrowck = mir_borrowck;
}
// Since mir_borrowck does not have access to any other state, we need to use a
+# needs-llvm-components: x86 arm
+
-include ../tools.mk
all: default
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc"
+DYLIB_NAME := $(shell echo | $(RUSTC) --crate-name foobar_macro --crate-type dylib --print file-names -)
+
+all:
+ $(RUSTC) src/proc.rs --crate-name foobar_macro --edition=2021 --crate-type proc-macro --emit=dep-info,link
+
+ $(RUSTC) src/lib.rs --crate-name foobar --edition=2021 --crate-type lib --emit=dep-info,link
+
+ $(RUSTDOC) examples/ex.rs --crate-name ex --crate-type bin --output $(OUTPUT_DIR) \
+ --extern foobar=$(TMPDIR)/libfoobar.rlib --extern foobar_macro=$(TMPDIR)/$(DYLIB_NAME) \
+ -Z unstable-options --scrape-examples-output-path $(TMPDIR)/ex.calls --scrape-examples-target-crate foobar
+
+ $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \
+ -Z unstable-options --with-examples $(TMPDIR)/ex.calls
+
+ $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
--- /dev/null
+extern crate foobar;
+extern crate foobar_macro;
+
+use foobar::*;
+use foobar_macro::*;
+
+a_proc_macro!(); // no
+
+#[an_attr_macro]
+fn a() {
+ f(); // no
+}
+
+#[an_attr_macro(with_span)]
+fn b() {
+ f(); // yes
+}
+
+fn c() {
+ a_rules_macro!(f()); // yes
+}
+
+fn d() {
+ a_rules_macro!(()); // no
+}
+
+fn main(){}
--- /dev/null
+// Scraped example should only include line numbers for items b and c in ex.rs
+// @!has foobar/fn.f.html '//*[@class="line-numbers"]' '14'
+// @has foobar/fn.f.html '//*[@class="line-numbers"]' '15'
+// @has foobar/fn.f.html '//*[@class="line-numbers"]' '21'
+// @!has foobar/fn.f.html '//*[@class="line-numbers"]' '22'
+
+pub fn f() {}
+
+#[macro_export]
+macro_rules! a_rules_macro {
+ ($e:expr) => { ($e, foobar::f()); }
+}
--- /dev/null
+extern crate proc_macro;
+use proc_macro::*;
+
+#[proc_macro]
+pub fn a_proc_macro(_item: TokenStream) -> TokenStream {
+ "fn ex() { foobar::f(); }".parse().unwrap()
+}
+
+// inserts foobar::f() to the end of the function
+#[proc_macro_attribute]
+pub fn an_attr_macro(attr: TokenStream, item: TokenStream) -> TokenStream {
+ let new_call: TokenStream = "foobar::f();".parse().unwrap();
+
+ let mut tokens = item.into_iter();
+
+ let fn_tok = tokens.next().unwrap();
+ let ident_tok = tokens.next().unwrap();
+ let args_tok = tokens.next().unwrap();
+ let body = match tokens.next().unwrap() {
+ TokenTree::Group(g) => {
+ let new_g = Group::new(g.delimiter(), new_call);
+ let mut outer_g = Group::new(
+ g.delimiter(),
+ [TokenTree::Group(g.clone()), TokenTree::Group(new_g)].into_iter().collect(),
+ );
+
+ if attr.to_string() == "with_span" {
+ outer_g.set_span(g.span());
+ }
+
+ TokenTree::Group(outer_g)
+ }
+ _ => unreachable!(),
+ };
+
+ let tokens = vec![fn_tok, ident_tok, args_tok, body].into_iter().collect::<TokenStream>();
+
+ tokens
+}
# that it is compiled with the expectation that pthreads is dynamically
# linked as a DLL and will fail to link with a statically linked libpthread.
#
- # So we end up with the following hack: we link use static-nobundle to only
+ # So we end up with the following hack: we link use static:-bundle to only
# link the parts of libstdc++ that we actually use, which doesn't include
# the dependency on the pthreads DLL.
- EXTRARSCXXFLAGS := -l static-nobundle=stdc++
+ EXTRARSCXXFLAGS := -l static:-bundle=stdc++ -Z unstable-options
endif
else
ifeq ($(UNAME),Darwin)
--- /dev/null
+include ../../run-make-fulldeps/tools.mk
+
+DYLIB_NAME := $(shell echo | $(RUSTC) --crate-name foo --crate-type dylib --print file-names -)
+
+all:
+ echo >> $(TMPDIR)/$(DYLIB_NAME)
+ $(RUSTC) --crate-type lib --extern foo=$(TMPDIR)/$(DYLIB_NAME) bar.rs 2>&1 | $(CGREP) 'invalid metadata files for crate `foo`'
--- /dev/null
+extern crate foo;
// Tests that linking to C++ code with global destructors works.
-// For linking libstdc++ on MinGW
-#![cfg_attr(all(windows, target_env = "gnu"), feature(static_nobundle))]
-
extern "C" {
fn get() -> u32;
}
--- /dev/null
+deps := ex
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
--- /dev/null
+pub struct Foo([usize; foobar::f()]);
+fn main() {}
--- /dev/null
+pub const fn f() -> usize { 5 }
// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]//*[@class="prev"]' ''
// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' ''
+// @has src/ex/ex.rs.html
+// @has foobar/fn.ok.html '//a[@href="../src/ex/ex.rs.html#2"]' ''
pub fn ok() {}
fn main() {
- foobar::ok();
+ foobar::ok(0);
// this is a
+ // ..
+
// BIG
// item
fn main() {
- foobar::ok();
+ foobar::ok(1);
// small item
}
+
+fn f() {
+ foobar::ok(2);
+}
// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' 'ex2'
// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' 'ex1'
+// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '1'
+// @has foobar/fn.ok.html '//*[@class="highlight"]' '2'
+// @has foobar/fn.ok.html '//*[@class="highlight focus"]' '0'
-pub fn ok() {}
+pub fn ok(_x: i32) {}
--- /dev/null
+// This test check that headers (a) have the correct heading level, (b) are the right size,
+// and (c) have the correct underlining (or absence of underlining).
+// The sizes may change as design changes, but try to make sure a lower header is never bigger than
+// its parent headers. Also make sure lower headers don't have underlines when their parents lack
+// an underline.
+// Most of these sizes are set in CSS in `em` units, so here's a conversion chart based on our
+// default 16px font size:
+// 24px 1.5em
+// 22.4px 1.4em
+// 20.8px 1.3em
+// 18.4px 1.15em
+// 17.6px 1.1em
+// 16px 1em
+// 15.2px 0.95em
+goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
+
+assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "17.6px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#fields", {"font-size": "22.4px"})
+assert-css: ("h2#fields", {"border-bottom-width": "1px"})
+assert-css: ("h3#title-for-field", {"font-size": "20.8px"})
+assert-css: ("h3#title-for-field", {"border-bottom-width": "0px"})
+assert-css: ("h4#sub-heading-for-field", {"font-size": "16px"})
+assert-css: ("h4#sub-heading-for-field", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#title-for-struct-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-struct-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-struct-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-struct-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"})
+
+goto: file://|DOC_PATH|/test_docs/enum.HeavilyDocumentedEnum.html
+
+assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "17.6px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#variants", {"font-size": "22.4px"})
+assert-css: ("h2#variants", {"border-bottom-width": "1px"})
+
+assert-css: ("h3#none-prose-title", {"font-size": "20.8px"})
+assert-css: ("h3#none-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h4#none-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h4#none-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h3#wrapped-prose-title", {"font-size": "20.8px"})
+assert-css: ("h3#wrapped-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h4#wrapped-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h4#wrapped-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#wrapped0-prose-title", {"font-size": "16px"})
+assert-css: ("h4#wrapped0-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h5#wrapped0-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h5#wrapped0-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#structy-prose-title", {"font-size": "16px"})
+assert-css: ("h4#structy-prose-title", {"border-bottom-width": "0px"})
+assert-css: ("h5#structy-prose-sub-heading", {"font-size": "16px"})
+assert-css: ("h5#structy-prose-sub-heading", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
+assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
+
+assert-css: ("h4#title-for-enum-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-enum-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-enum-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-enum-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
+
+assert-text: (".sidebar .others h3", "Modules")
+assert-css: (".sidebar .others h3", {"border-bottom-width": "1px"}, ALL)
+
+goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html
+
+assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#fields", {"font-size": "22.4px"})
+assert-css: ("h2#fields", {"border-bottom-width": "1px"})
+
+assert-css: ("h3#title-for-union-variant", {"font-size": "20.8px"})
+assert-css: ("h3#title-for-union-variant", {"border-bottom-width": "0px"})
+assert-css: ("h4#sub-heading-for-union-variant", {"font-size": "16px"})
+assert-css: ("h4#sub-heading-for-union-variant", {"border-bottom-width": "0px"})
+
+assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
+
+assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
+assert-css: ("h4#title-for-union-impl-doc", {"font-size": "16px"})
+assert-css: ("h4#title-for-union-impl-doc", {"border-bottom-width": "0px"})
+assert-css: ("h5#sub-heading-for-union-impl-doc", {"font-size": "16px"})
+assert-css: ("h5#sub-heading-for-union-impl-doc", {"border-bottom-width": "0px"})
+
+assert-css: ("h5#title-for-union-impl-item-doc", {"font-size": "16px"})
+assert-css: ("h5#title-for-union-impl-item-doc", {"border-bottom-width": "0px"})
+assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": "0px"})
+
+goto: file://|DOC_PATH|/test_docs/macro.heavily_documented_macro.html
+
+assert-css: ("h1.fqn", {"font-size": "24px"})
+assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+
+assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
--- /dev/null
+// When JavaScript is disabled, we hide the search bar, because it
+// can't be used without JS.
+javascript: false
+
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+assert-css: (".sub", {"display": "none"})
// This test checks that the correct font is used on module items (in index.html pages).
goto: file://|DOC_PATH|/test_docs/index.html
-assert-css: (".item-table .module-item a", {"font-family": '"Fira Sans", Arial, sans-serif'}, ALL)
-assert-css: (".item-table .docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'}, ALL)
+assert-css: (".item-table .module-item a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ALL)
+assert-css: (".item-table .docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ALL)
// modules
-assert-css: ("#modules + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#modules + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#modules + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#modules + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
// structs
-assert-css: ("#structs + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#structs + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#structs + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#structs + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
// enums
-assert-css: ("#enums + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#enums + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#enums + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#enums + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
// traits
-assert-css: ("#traits + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#traits + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#traits + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#traits + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
// functions
-assert-css: ("#functions + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#functions + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#functions + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#functions + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
// keywords
-assert-css: ("#keywords + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, sans-serif'})
-assert-css: ("#keywords + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", "Noto Sans KR", serif'})
+assert-css: ("#keywords + .item-table .item-left a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'})
+assert-css: ("#keywords + .item-table .item-right.docblock-short", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'})
--- /dev/null
+// The goal of this test is to ensure that the tooltip `.information` class doesn't
+// have overflow and max-width CSS rules set because they create a bug in firefox on
+// mac. For more information: https://github.com/rust-lang/rust/issues/89185
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+assert-css: (".docblock > .information", {
+ "overflow-x": "visible",
+ "max-width": "none"
+}, ALL)
assert-count: (".sidebar .location", 1)
assert-text: (".sidebar-elems > #all-types", "See all test_docs's items")
// We check that we have the crates list and that the "current" on is "test_docs".
-assert-text: (".sidebar-elems > .crate > ul > li > a.current", "test_docs")
+assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs")
// And we're also supposed to have the list of items in the current module.
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Macros")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(3)", "Structs")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(4)", "Enums")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(5)", "Traits")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(6)", "Functions")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(7)", "Type Definitions")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(8)", "Keywords")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Modules")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(2)", "Macros")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(3)", "Structs")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(4)", "Enums")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(5)", "Traits")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(6)", "Functions")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(7)", "Type Definitions")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(8)", "Unions")
+assert-text: (".sidebar-elems .items > ul > li:nth-child(9)", "Keywords")
assert-text: ("#structs + .item-table .item-left > a", "Foo")
click: "#structs + .item-table .item-left > a"
assert-false: ".sidebar-elems > .crate"
// We now go back to the crate page to click on the "lib2" crate link.
goto: file://|DOC_PATH|/test_docs/index.html
-click: ".sidebar-elems > .crate > ul > li:first-child > a"
+click: ".sidebar-elems .crate > ul > li:first-child > a"
// PAGE: lib2/index.html
goto: file://|DOC_PATH|/lib2/index.html
assert-text: (".sidebar > .location", "Crate lib2")
// We check that we have the crates list and that the "current" on is now "lib2".
-assert-text: (".sidebar-elems > .crate > ul > li > a.current", "lib2")
+assert-text: (".sidebar-elems .crate > ul > li > a.current", "lib2")
// We now go to the "foobar" function page.
assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
goto: ./sub_module/sub_sub_module/index.html
assert-text: (".sidebar > .location", "Module sub_sub_module")
// We check that we don't have the crate list.
-assert-false: ".sidebar-elems > .crate"
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Functions")
+assert-false: ".sidebar-elems .crate"
+assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Functions")
assert-text: ("#functions + .item-table .item-left > a", "foo")
}
pub use crate::repro as repro2;
+
+/// # Top-doc Prose title
+///
+/// Text below title.
+///
+/// ## Top-doc Prose sub-heading
+///
+/// Text below sub-heading.
+///
+/// ### Top-doc Prose sub-sub-heading
+///
+/// Text below sub-sub-heading
+pub struct HeavilyDocumentedStruct {
+ /// # Title for field
+ /// ## Sub-heading for field
+ pub nothing: (),
+}
+
+/// # Title for struct impl doc
+///
+/// Text below heading.
+///
+/// ## Sub-heading for struct impl doc
+///
+/// Text below sub-heading.
+///
+/// ### Sub-sub-heading for struct impl doc
+///
+/// Text below sub-sub-heading.
+///
+impl HeavilyDocumentedStruct {
+ /// # Title for struct impl-item doc
+ /// Text below title.
+ /// ## Sub-heading for struct impl-item doc
+ /// Text below sub-heading.
+ /// ### Sub-sub-heading for struct impl-item doc
+ /// Text below sub-sub-heading.
+ pub fn do_nothing() {}
+}
+
+/// # Top-doc Prose title
+///
+/// Text below title.
+///
+/// ## Top-doc Prose sub-heading
+///
+/// Text below sub-heading.
+///
+/// ### Top-doc Prose sub-sub-heading
+///
+/// Text below sub-sub-heading
+pub enum HeavilyDocumentedEnum {
+ /// # None prose title
+ /// ## None prose sub-heading
+ None,
+ /// # Wrapped prose title
+ /// ## Wrapped prose sub-heading
+ Wrapped(
+ /// # Wrapped.0 prose title
+ /// ## Wrapped.0 prose sub-heading
+ String,
+ String,
+ ),
+ Structy {
+ /// # Structy prose title
+ /// ## Structy prose sub-heading
+ alpha: String,
+ beta: String,
+ },
+}
+
+/// # Title for enum impl doc
+///
+/// Text below heading.
+///
+/// ## Sub-heading for enum impl doc
+///
+/// Text below sub-heading.
+///
+/// ### Sub-sub-heading for enum impl doc
+///
+/// Text below sub-sub-heading.
+///
+impl HeavilyDocumentedEnum {
+ /// # Title for enum impl-item doc
+ /// Text below title.
+ /// ## Sub-heading for enum impl-item doc
+ /// Text below sub-heading.
+ /// ### Sub-sub-heading for enum impl-item doc
+ /// Text below sub-sub-heading.
+ pub fn do_nothing() {}
+}
+
+/// # Top-doc prose title
+///
+/// Text below heading.
+///
+/// ## Top-doc prose sub-heading
+///
+/// Text below heading.
+pub union HeavilyDocumentedUnion {
+ /// # Title for union variant
+ /// ## Sub-heading for union variant
+ pub nothing: (),
+ pub something: f32,
+}
+
+/// # Title for union impl doc
+/// ## Sub-heading for union impl doc
+impl HeavilyDocumentedUnion {
+ /// # Title for union impl-item doc
+ /// ## Sub-heading for union impl-item doc
+ pub fn do_nothing() {}
+}
+
+/// # Top-doc prose title
+///
+/// Text below heading.
+///
+/// ## Top-doc prose sub-heading
+///
+/// Text below heading.
+#[macro_export]
+macro_rules! heavily_documented_macro {
+ () => {};
+}
// exact-check
const QUERY = [
- '"R<P>"',
- '"P"',
- 'P',
- '"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
+ '"R<P>"',
+ '"P"',
+ 'P',
+ '"ExtraCreditStructMulti<ExtraCreditInnerMulti, ExtraCreditInnerMulti>"',
+ 'TraitCat',
+ 'TraitDog',
];
const EXPECTED = [
{
'returned': [
{ 'path': 'generics', 'name': 'alef' },
+ { 'path': 'generics', 'name': 'bet' },
],
'in_args': [
{ 'path': 'generics', 'name': 'alpha' },
+ { 'path': 'generics', 'name': 'beta' },
],
},
{
],
'returned': [],
},
+ {
+ 'in_args': [
+ { 'path': 'generics', 'name': 'gamma' },
+ ],
+ },
+ {
+ 'in_args': [
+ { 'path': 'generics', 'name': 'gamma' },
+ ],
+ },
];
pub fn redherringmatchforextracredit(
_param: ExtraCreditStructMulti<ExtraCreditInnerMulti, ()>
) { loop {} }
+
+pub trait TraitCat {}
+pub trait TraitDog {}
+
+pub fn gamma<T: TraitCat + TraitDog>(t: T) {}
|
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
- = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+ = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
error: this attribute can only be applied at the crate level
--> $DIR/invalid-doc-attr.rs:15:12
|
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
- = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+ = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
error: aborting due to 6 previous errors
--- /dev/null
+// check-pass
+
+// ICE found in https://github.com/rust-lang/rust/issues/83123
+
+pub struct Attribute;
+
+pub struct Map<'hir> {}
+impl<'hir> Map<'hir> {
+ pub fn attrs(&self) -> &'hir [Attribute] { &[] }
+}
+
+pub struct List<T>(T);
+
+impl<T> std::ops::Deref for List<T> {
+ type Target = [T];
+ fn deref(&self) -> &[T] {
+ &[]
+ }
+}
--- /dev/null
+// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
+// levels and across multiple crates.
+// For `Deref` on non-foreign types, look at `deref-recursive.rs`.
+
+// @has 'foo/struct.Foo.html'
+// @has '-' '//*[@id="deref-methods-PathBuf"]' 'Methods from Deref<Target = PathBuf>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.as_path"]' 'pub fn as_path(&self)'
+// @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.exists"]' 'exists'
+
+#![crate_name = "foo"]
+
+use std::ops::Deref;
+use std::path::PathBuf;
+
+pub struct Foo(PathBuf);
+
+impl Deref for Foo {
+ type Target = PathBuf;
+ fn deref(&self) -> &PathBuf { &self.0 }
+}
--- /dev/null
+// #26207: Show all methods reachable via Deref impls, recursing through multiple dereferencing
+// levels if needed.
+// For `Deref` on foreign types, look at `deref-recursive-pathbuf.rs`.
+
+// @has 'foo/struct.Foo.html'
+// @has '-' '//*[@id="deref-methods-Bar"]' 'Methods from Deref<Target = Bar>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.bar"]' 'pub fn bar(&self)'
+// @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
+// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.baz"]' 'baz'
+
+#![crate_name = "foo"]
+
+use std::ops::Deref;
+
+pub struct Foo(Bar);
+pub struct Bar(Baz);
+pub struct Baz;
+
+impl Deref for Foo {
+ type Target = Bar;
+ fn deref(&self) -> &Bar { &self.0 }
+}
+
+impl Deref for Bar {
+ type Target = Baz;
+ fn deref(&self) -> &Baz { &self.0 }
+}
+
+impl Bar {
+ /// This appears under `Foo` methods
+ pub fn bar(&self) {}
+}
+
+impl Baz {
+ /// This should also appear in `Foo` methods when recursing
+ pub fn baz(&self) {}
+}
#![crate_name = "foo"]
// @has 'foo/struct.Bar.html'
-// @has '-' '//*[@id="deref-methods"]' 'Methods from Deref<Target = FooJ>'
+// @has '-' '//*[@id="deref-methods-FooJ"]' 'Methods from Deref<Target = FooJ>'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_a"]' 'pub fn foo_a(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_b"]' 'pub fn foo_b(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
// @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
-// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods"]' 'Methods from Deref<Target=FooJ>'
+// @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b'
// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c'
--- /dev/null
+#![feature(doc_auto_cfg)]
+
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @has - '//*[@class="item-info"]/*[@class="stab portability"]' 'non-test'
+#[cfg(not(test))]
+pub fn foo() {}
#![crate_name = "oud"]
-#![feature(doc_cfg, doc_cfg_hide)]
+#![feature(doc_auto_cfg, doc_cfg, doc_cfg_hide)]
#![doc(cfg_hide(feature = "solecism"))]
#![crate_name = "funambulism"]
-#![feature(doc_cfg)]
+#![feature(doc_auto_cfg, doc_cfg)]
// @has 'funambulism/struct.Disorbed.html'
// @count - '//*[@class="stab portability"]' 1
--- /dev/null
+#![feature(doc_cfg)]
+
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @count - '//*[@class="item-info"]/*[@class="stab portability"]' 0
+#[cfg(not(test))]
+pub fn foo() {}
--- /dev/null
+#![crate_name = "foo"]
+#![no_std]
+
+// @has 'foo/fn.foo.html'
+// @has - '//*[@class="docblock"]' 'inc2 x'
+#[doc = include_str!("short-line.md")]
+pub fn foo() {}
fn deref(&self) -> &B { todo!() }
}
-// @!has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
+// @has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
impl Deref for B {
type Target = C;
fn deref(&self) -> &C { todo!() }
use std::ops::Deref;
+// Cyclic deref with the parent (which is not the top parent).
pub struct A;
pub struct B;
+pub struct C;
+
+impl C {
+ pub fn c(&self) {}
+}
// @has recursive_deref/struct.A.html '//h3[@class="code-header in-band"]' 'impl Deref for A'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
impl Deref for A {
type Target = B;
}
// @has recursive_deref/struct.B.html '//h3[@class="code-header in-band"]' 'impl Deref for B'
+// @has '-' '//*[@class="impl-items"]//*[@id="method.c"]' 'pub fn c(&self)'
impl Deref for B {
- type Target = A;
+ type Target = C;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.C.html '//h3[@class="code-header in-band"]' 'impl Deref for C'
+impl Deref for C {
+ type Target = B;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// Cyclic deref with the grand-parent (which is not the top parent).
+pub struct D;
+pub struct E;
+pub struct F;
+pub struct G;
+
+impl G {
+ // There is no "self" parameter so it shouldn't be listed!
+ pub fn g() {}
+}
+
+// @has recursive_deref/struct.D.html '//h3[@class="code-header in-band"]' 'impl Deref for D'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for D {
+ type Target = E;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.E.html '//h3[@class="code-header in-band"]' 'impl Deref for E'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for E {
+ type Target = F;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.F.html '//h3[@class="code-header in-band"]' 'impl Deref for F'
+// We also check that `G::g` method isn't rendered because there is no `self` argument.
+// @!has '-' '//*[@id="deref-methods-G"]'
+impl Deref for F {
+ type Target = G;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.G.html '//h3[@class="code-header in-band"]' 'impl Deref for G'
+impl Deref for G {
+ type Target = E;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// Cyclic deref with top parent.
+pub struct H;
+pub struct I;
+
+impl I {
+ // There is no "self" parameter so it shouldn't be listed!
+ pub fn i() {}
+}
+
+// @has recursive_deref/struct.H.html '//h3[@class="code-header in-band"]' 'impl Deref for H'
+// @!has '-' '//*[@id="deref-methods-I"]'
+impl Deref for H {
+ type Target = I;
+
+ fn deref(&self) -> &Self::Target {
+ panic!()
+ }
+}
+
+// @has recursive_deref/struct.I.html '//h3[@class="code-header in-band"]' 'impl Deref for I'
+impl Deref for I {
+ type Target = H;
fn deref(&self) -> &Self::Target {
panic!()
+++ /dev/null
-// compile-flags: -Z unstable-options
-
-#![feature(rustc_private)]
-#![deny(rustc::potential_query_instability)]
-
-extern crate rustc_data_structures;
-
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-
-fn main() {
- let mut x = FxHashMap::<u32, i32>::default();
-
- for _ in x.drain() {}
- //~^ ERROR using `drain` can result in unstable
-
- for _ in x.iter() {}
- //~^ ERROR using `iter`
-
- for _ in Some(&mut x).unwrap().iter_mut() {}
- //~^ ERROR using `iter_mut`
-
- for _ in x {}
- //~^ ERROR using `into_iter`
-}
+++ /dev/null
-error: using `drain` can result in unstable query results
- --> $DIR/query_stability.rs:13:16
- |
-LL | for _ in x.drain() {}
- | ^^^^^
- |
-note: the lint level is defined here
- --> $DIR/query_stability.rs:4:9
- |
-LL | #![deny(rustc::potential_query_instability)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
-
-error: using `iter` can result in unstable query results
- --> $DIR/query_stability.rs:16:16
- |
-LL | for _ in x.iter() {}
- | ^^^^
- |
- = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
-
-error: using `iter_mut` can result in unstable query results
- --> $DIR/query_stability.rs:19:36
- |
-LL | for _ in Some(&mut x).unwrap().iter_mut() {}
- | ^^^^^^^^
- |
- = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
-
-error: using `into_iter` can result in unstable query results
- --> $DIR/query_stability.rs:22:14
- |
-LL | for _ in x {}
- | ^
- |
- = note: if you believe this case to be fine, allow this lint and add a comment explaining your rationale
-
-error: aborting due to 4 previous errors
-
+++ /dev/null
-// compile-flags: -Z unstable-options
-
-#![feature(rustc_attrs)]
-
-#[rustc_lint_query_instability]
-//~^ ERROR attribute should be applied to a function
-struct Foo;
-
-impl Foo {
- #[rustc_lint_query_instability(a)]
- //~^ ERROR malformed `rustc_lint_query_instability`
- fn bar() {}
-}
-
-fn main() {}
+++ /dev/null
-error: malformed `rustc_lint_query_instability` attribute input
- --> $DIR/query_stability_incorrect.rs:10:5
- |
-LL | #[rustc_lint_query_instability(a)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_lint_query_instability]`
-
-error: attribute should be applied to a function
- --> $DIR/query_stability_incorrect.rs:5:1
- |
-LL | #[rustc_lint_query_instability]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |
-LL | struct Foo;
- | ----------- not a function
-
-error: aborting due to 2 previous errors
-
//~^ WARNING lint name `test_lint` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
+//~| WARNING lint name `test_lint` is deprecated and may not have an effect in the future
#![deny(clippy_group)]
//~^ WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
+//~| WARNING lint name `clippy_group` is deprecated and may not have an effect in the future
fn lintme() { } //~ ERROR item is named 'lintme'
//~^ WARNING lint name `test_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
+//~| WARNING lint name `test_group` is deprecated and may not have an effect in the future
#[deny(this_lint_does_not_exist)] //~ WARNING unknown lint: `this_lint_does_not_exist`
fn hello() {
fn lintmetoo() { }
= note: `#[warn(renamed_and_removed_lints)]` on by default
warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^ help: change it to: `clippy::group`
warning: lint name `test_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:29:9
+ --> $DIR/lint-tool-test.rs:31:9
|
LL | #[allow(test_group)]
| ^^^^^^^^^^ help: change it to: `clippy::test_group`
warning: unknown lint: `this_lint_does_not_exist`
- --> $DIR/lint-tool-test.rs:33:8
+ --> $DIR/lint-tool-test.rs:36:8
|
LL | #[deny(this_lint_does_not_exist)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^ help: change it to: `clippy::test_lint`
warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^ help: change it to: `clippy::group`
warning: lint name `test_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:29:9
+ --> $DIR/lint-tool-test.rs:31:9
|
LL | #[allow(test_group)]
| ^^^^^^^^^^ help: change it to: `clippy::test_group`
| ^^^^^^^^^ help: change it to: `clippy::test_lint`
warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^ help: change it to: `clippy::group`
error: item is named 'lintme'
- --> $DIR/lint-tool-test.rs:18:1
+ --> $DIR/lint-tool-test.rs:20:1
|
LL | fn lintme() { }
| ^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^
= note: `#[deny(clippy::test_lint)]` implied by `#[deny(clippy::group)]`
error: item is named 'lintmetoo'
- --> $DIR/lint-tool-test.rs:26:5
+ --> $DIR/lint-tool-test.rs:28:5
|
LL | fn lintmetoo() { }
| ^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/lint-tool-test.rs:13:9
+ --> $DIR/lint-tool-test.rs:14:9
|
LL | #![deny(clippy_group)]
| ^^^^^^^^^^^^
= note: `#[deny(clippy::test_group)]` implied by `#[deny(clippy::group)]`
warning: lint name `test_group` is deprecated and may not have an effect in the future.
- --> $DIR/lint-tool-test.rs:29:9
+ --> $DIR/lint-tool-test.rs:31:9
|
LL | #[allow(test_group)]
| ^^^^^^^^^^ help: change it to: `clippy::test_group`
-error: aborting due to 2 previous errors; 11 warnings emitted
+warning: lint name `test_lint` is deprecated and may not have an effect in the future.
+ --> $DIR/lint-tool-test.rs:9:23
+ |
+LL | #![cfg_attr(foo, warn(test_lint))]
+ | ^^^^^^^^^ help: change it to: `clippy::test_lint`
+
+warning: lint name `clippy_group` is deprecated and may not have an effect in the future.
+ --> $DIR/lint-tool-test.rs:14:9
+ |
+LL | #![deny(clippy_group)]
+ | ^^^^^^^^^^^^ help: change it to: `clippy::group`
+
+warning: lint name `test_group` is deprecated and may not have an effect in the future.
+ --> $DIR/lint-tool-test.rs:31:9
+ |
+LL | #[allow(test_group)]
+ | ^^^^^^^^^^ help: change it to: `clippy::test_group`
+
+error: aborting due to 2 previous errors; 14 warnings emitted
LL | extern "x86-interrupt" fn x86() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-warning: use of calling convention not supported on this target
+error[E0570]: `"thiscall"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:43:1
|
-LL | extern "stdcall" fn stdcall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: `#[warn(unsupported_calling_conventions)]` 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 #87678 <https://github.com/rust-lang/rust/issues/87678>
+LL | extern "thiscall" fn thiscall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of calling convention not supported on this target
- --> $DIR/unsupported.rs:50:1
+ --> $DIR/unsupported.rs:47:1
|
-LL | extern "thiscall" fn thiscall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "stdcall" fn stdcall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: `#[warn(unsupported_calling_conventions)]` 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 #87678 <https://github.com/rust-lang/rust/issues/87678>
-error: aborting due to 7 previous errors; 2 warnings emitted
+error: aborting due to 8 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0570`.
LL | extern "x86-interrupt" fn x86() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-warning: use of calling convention not supported on this target
+error[E0570]: `"thiscall"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:43:1
|
-LL | extern "stdcall" fn stdcall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: `#[warn(unsupported_calling_conventions)]` 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 #87678 <https://github.com/rust-lang/rust/issues/87678>
+LL | extern "thiscall" fn thiscall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of calling convention not supported on this target
- --> $DIR/unsupported.rs:50:1
+ --> $DIR/unsupported.rs:47:1
|
-LL | extern "thiscall" fn thiscall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "stdcall" fn stdcall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: `#[warn(unsupported_calling_conventions)]` 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 #87678 <https://github.com/rust-lang/rust/issues/87678>
-error: aborting due to 6 previous errors; 2 warnings emitted
+error: aborting due to 7 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0570`.
extern "x86-interrupt" fn x86() {}
//[aarch64]~^ ERROR is not a supported ABI
//[arm]~^^ ERROR is not a supported ABI
-extern "stdcall" fn stdcall() {}
-//[x64]~^ WARN use of calling convention not supported
-//[x64]~^^ WARN this was previously accepted
-//[aarch64]~^^^ WARN use of calling convention not supported
-//[aarch64]~^^^^ WARN this was previously accepted
-//[arm]~^^^^^ WARN use of calling convention not supported
-//[arm]~^^^^^^ WARN this was previously accepted
extern "thiscall" fn thiscall() {}
+//[x64]~^ ERROR is not a supported ABI
+//[aarch64]~^^ ERROR is not a supported ABI
+//[arm]~^^^ ERROR is not a supported ABI
+extern "stdcall" fn stdcall() {}
//[x64]~^ WARN use of calling convention not supported
//[x64]~^^ WARN this was previously accepted
//[aarch64]~^^^ WARN use of calling convention not supported
LL | extern "avr-interrupt" fn avr() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-warning: use of calling convention not supported on this target
+error[E0570]: `"thiscall"` is not a supported ABI for the current target
--> $DIR/unsupported.rs:43:1
|
-LL | extern "stdcall" fn stdcall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: `#[warn(unsupported_calling_conventions)]` 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 #87678 <https://github.com/rust-lang/rust/issues/87678>
+LL | extern "thiscall" fn thiscall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: use of calling convention not supported on this target
- --> $DIR/unsupported.rs:50:1
+ --> $DIR/unsupported.rs:47:1
|
-LL | extern "thiscall" fn thiscall() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "stdcall" fn stdcall() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
+ = note: `#[warn(unsupported_calling_conventions)]` 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 #87678 <https://github.com/rust-lang/rust/issues/87678>
-error: aborting due to 6 previous errors; 2 warnings emitted
+error: aborting due to 7 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0570`.
+++ /dev/null
-// run-pass
-
-struct X {
- x: isize
-}
-
-fn f1(a: &mut X, b: &mut isize, c: isize) -> isize {
- let r = a.x + *b + c;
- a.x = 0;
- *b = 10;
- return r;
-}
-
-fn f2<F>(a: isize, f: F) -> isize where F: FnOnce(isize) { f(1); return a; }
-
-pub fn main() {
- let mut a = X {x: 1};
- let mut b = 2;
- let c = 3;
- assert_eq!(f1(&mut a, &mut b, c), 6);
- assert_eq!(a.x, 0);
- assert_eq!(b, 10);
- assert_eq!(f2(a.x, |_| a.x = 50), 0);
- assert_eq!(a.x, 50);
-}
--- /dev/null
+// run-pass
+// pretty-expanded FIXME #23616
+
+pub fn main() {
+ let _x: &mut [isize] = &mut [ 1, 2, 3 ];
+}
// only-aarch64
// compile-flags: -C target-feature=+fp
-#![feature(asm)]
+#![feature(asm, asm_const, asm_sym)]
fn main() {
let mut foo = 0;
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
fn const_generic<const X: usize>() -> usize {
unsafe {
// only-aarch64
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
fn main() {
let mut foo = 0;
// only-linux
// run-pass
-#![feature(asm, thread_local)]
+#![feature(asm, thread_local, asm_sym)]
extern "C" fn f1() -> i32 {
111
std::thread::spawn(|| {
assert_eq!(static_addr!(S1), &S1 as *const u32);
assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
- }).join().unwrap();
+ })
+ .join()
+ .unwrap();
}
// only-aarch64
-#![feature(asm, repr_simd, never_type)]
+#![feature(asm, repr_simd, never_type, asm_sym)]
#[repr(simd)]
#[derive(Clone, Copy)]
// only-aarch64
// compile-flags: -C target-feature=+neon
-#![feature(asm, global_asm, repr_simd, stdsimd)]
+#![feature(asm, global_asm, repr_simd, stdsimd, asm_const)]
use std::arch::aarch64::float64x2_t;
#[repr(simd)]
#[derive(Copy, Clone)]
-struct Simd256bit(f64, f64,f64, f64);
+struct Simd256bit(f64, f64, f64, f64);
fn main() {
let f64x2: float64x2_t = unsafe { std::mem::transmute(0i128) };
asm!("{:b}", in(vreg) 0u64);
asm!("{:d}", in(vreg_low16) f64x2);
-
// Template modifier suggestions for sub-registers
asm!("{}", in(reg) 0u8);
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:48:15
+ --> $DIR/type-check-3.rs:47:15
|
LL | asm!("{}", in(reg) 0u8);
| ^^ --- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:50:15
+ --> $DIR/type-check-3.rs:49:15
|
LL | asm!("{}", in(reg) 0u16);
| ^^ ---- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:52:15
+ --> $DIR/type-check-3.rs:51:15
|
LL | asm!("{}", in(reg) 0i32);
| ^^ ---- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:54:15
+ --> $DIR/type-check-3.rs:53:15
|
LL | asm!("{}", in(reg) 0f32);
| ^^ ---- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:57:15
+ --> $DIR/type-check-3.rs:56:15
|
LL | asm!("{}", in(vreg) 0i16);
| ^^ ---- for this argument
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:59:15
+ --> $DIR/type-check-3.rs:58:15
|
LL | asm!("{}", in(vreg) 0f32);
| ^^ ---- for this argument
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:61:15
+ --> $DIR/type-check-3.rs:60:15
|
LL | asm!("{}", in(vreg) 0f64);
| ^^ ---- for this argument
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:63:15
+ --> $DIR/type-check-3.rs:62:15
|
LL | asm!("{}", in(vreg_low16) 0f64);
| ^^ ---- for this argument
= help: or use the `v` modifier to keep the default formatting of `v0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:66:15
+ --> $DIR/type-check-3.rs:65:15
|
LL | asm!("{0} {0}", in(reg) 0i16);
| ^^^ ^^^ ---- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
warning: formatting may not be suitable for sub-register argument
- --> $DIR/type-check-3.rs:68:15
+ --> $DIR/type-check-3.rs:67:15
|
LL | asm!("{0} {0:x}", in(reg) 0i16);
| ^^^ ---- for this argument
= help: or use the `x` modifier to keep the default formatting of `x0`
error: type `i128` cannot be used with this register class
- --> $DIR/type-check-3.rs:73:28
+ --> $DIR/type-check-3.rs:72:28
|
LL | asm!("{}", in(reg) 0i128);
| ^^^^^
= note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
error: type `float64x2_t` cannot be used with this register class
- --> $DIR/type-check-3.rs:75:28
+ --> $DIR/type-check-3.rs:74:28
|
LL | asm!("{}", in(reg) f64x2);
| ^^^^^
= note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
error: type `Simd256bit` cannot be used with this register class
- --> $DIR/type-check-3.rs:77:29
+ --> $DIR/type-check-3.rs:76:29
|
LL | asm!("{}", in(vreg) f64x4);
| ^^^^^
= note: register class `vreg` supports these types: i8, i16, i32, i64, f32, f64, i8x8, i16x4, i32x2, i64x1, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:88:33
+ --> $DIR/type-check-3.rs:87:33
|
LL | asm!("{:x}", inout(reg) 0u32 => val_f32);
| ^^^^ ^^^^^^^ type `f32`
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:90:33
+ --> $DIR/type-check-3.rs:89:33
|
LL | asm!("{:x}", inout(reg) 0u32 => val_ptr);
| ^^^^ ^^^^^^^ type `*mut u8`
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error: incompatible types for asm inout argument
- --> $DIR/type-check-3.rs:92:33
+ --> $DIR/type-check-3.rs:91:33
|
LL | asm!("{:x}", inout(reg) main => val_u32);
| ^^^^ ^^^^^^^ type `u32`
= note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:108:25
+ --> $DIR/type-check-3.rs:107:25
|
LL | global_asm!("{}", const S);
| ^
= help: consider extracting the value of the `static` to a `const`, and referring to that
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:111:35
+ --> $DIR/type-check-3.rs:110:35
|
LL | global_asm!("{}", const const_foo(S));
| ^
= help: consider extracting the value of the `static` to a `const`, and referring to that
error[E0013]: constants cannot refer to statics
- --> $DIR/type-check-3.rs:114:35
+ --> $DIR/type-check-3.rs:113:35
|
LL | global_asm!("{}", const const_bar(S));
| ^
// [aarch64_thirunsafeck] needs-llvm-components: aarch64
// [aarch64_mirunsafeck] needs-llvm-components: aarch64
-#![feature(no_core, lang_items, rustc_attrs)]
+#![feature(no_core, lang_items, rustc_attrs, asm_const)]
#![no_core]
#[rustc_builtin_macro]
// as both unused and possibly-uninitialized.
// check-pass
+// needs-asm-support
#![feature(asm)]
#![warn(unused)]
warning: unused variable: `x`
- --> $DIR/issue-89305.rs:11:13
+ --> $DIR/issue-89305.rs:12:13
|
LL | let x: () = asm!("nop");
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
note: the lint level is defined here
- --> $DIR/issue-89305.rs:7:9
+ --> $DIR/issue-89305.rs:8:9
|
LL | #![warn(unused)]
| ^^^^^^
#![feature(llvm_asm)]
#![feature(naked_functions)]
#![feature(or_patterns)]
+#![feature(asm_const, asm_sym)]
#![crate_type = "lib"]
#![allow(deprecated)] // llvm_asm!
#[repr(C)]
-pub struct P { x: u8, y: u16 }
+pub struct P {
+ x: u8,
+ y: u16,
+}
#[naked]
pub unsafe extern "C" fn patterns(
}
#[naked]
-pub unsafe extern "Rust" fn rust_abi() {
+pub unsafe fn rust_abi() {
//~^ WARN Rust ABI is unsupported in naked functions
asm!("", options(noreturn));
}
#[naked]
pub extern "C" fn valid_a<T>() -> T {
- unsafe { asm!("", options(noreturn)); }
+ unsafe {
+ asm!("", options(noreturn));
+ }
}
#[naked]
pub extern "C" fn valid_b() {
- unsafe { { {
- asm!("", options(noreturn)); ; ; ;
- } ; } ; }
+ unsafe {
+ {
+ {
+ asm!("", options(noreturn));
+ };
+ };
+ }
}
#[naked]
error: asm with the `pure` option must have at least one output
- --> $DIR/naked-functions.rs:131:14
+ --> $DIR/naked-functions.rs:135:14
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:18:5
+ --> $DIR/naked-functions.rs:22:5
|
LL | mut a: u32,
| ^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:20:5
+ --> $DIR/naked-functions.rs:24:5
|
LL | &b: &i32,
| ^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:22:6
+ --> $DIR/naked-functions.rs:26:6
|
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
| ^^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:24:5
+ --> $DIR/naked-functions.rs:28:5
|
LL | P { x, y }: P,
| ^^^^^^^^^^
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:34:5
+ --> $DIR/naked-functions.rs:38:5
|
LL | a + 1
| ^
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:31:1
+ --> $DIR/naked-functions.rs:35:1
|
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:40:31
+ --> $DIR/naked-functions.rs:44:31
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^
= help: follow the calling convention in asm block to use parameters
warning: only `const` and `sym` operands are supported in naked functions
- --> $DIR/naked-functions.rs:40:23
+ --> $DIR/naked-functions.rs:44:23
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:47:1
+ --> $DIR/naked-functions.rs:51:1
|
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: only `const` and `sym` operands are supported in naked functions
- --> $DIR/naked-functions.rs:67:10
+ --> $DIR/naked-functions.rs:71:10
|
LL | in(reg) a,
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:64:5
+ --> $DIR/naked-functions.rs:68:5
|
LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:54:1
+ --> $DIR/naked-functions.rs:58:1
|
LL | / pub unsafe extern "C" fn unsupported_operands() {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:80:1
+ --> $DIR/naked-functions.rs:84:1
|
LL | / pub extern "C" fn missing_assembly() {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:89:5
+ --> $DIR/naked-functions.rs:93:5
|
LL | asm!("");
| ^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:92:5
+ --> $DIR/naked-functions.rs:96:5
|
LL | asm!("");
| ^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:95:5
+ --> $DIR/naked-functions.rs:99:5
|
LL | asm!("");
| ^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:86:1
+ --> $DIR/naked-functions.rs:90:1
|
LL | / pub extern "C" fn too_many_asm_blocks() {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:106:11
+ --> $DIR/naked-functions.rs:110:11
|
LL | *&y
| ^
= help: follow the calling convention in asm block to use parameters
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:103:5
+ --> $DIR/naked-functions.rs:107:5
|
LL | / pub extern "C" fn inner(y: usize) -> usize {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: the LLVM-style inline assembly is unsupported in naked functions
- --> $DIR/naked-functions.rs:116:5
+ --> $DIR/naked-functions.rs:120:5
|
LL | llvm_asm!("");
| ^^^^^^^^^^^^^
= note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: naked functions must contain a single asm block
- --> $DIR/naked-functions.rs:113:1
+ --> $DIR/naked-functions.rs:117:1
|
LL | / unsafe extern "C" fn llvm() -> ! {
LL | |
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
- --> $DIR/naked-functions.rs:124:5
+ --> $DIR/naked-functions.rs:128:5
|
LL | asm!("", options(nomem, preserves_flags, noreturn));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
- --> $DIR/naked-functions.rs:131:5
+ --> $DIR/naked-functions.rs:135:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: asm in naked functions must use `noreturn` option
- --> $DIR/naked-functions.rs:131:5
+ --> $DIR/naked-functions.rs:135:5
|
LL | asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:140:15
+ --> $DIR/naked-functions.rs:144:15
|
LL | pub unsafe fn default_abi() {
| ^^^^^^^^^^^
= note: `#[warn(undefined_naked_function_abi)]` on by default
warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:146:29
+ --> $DIR/naked-functions.rs:150:15
|
-LL | pub unsafe extern "Rust" fn rust_abi() {
- | ^^^^^^^^
+LL | pub unsafe fn rust_abi() {
+ | ^^^^^^^^
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:180:1
+ --> $DIR/naked-functions.rs:190:1
|
LL | #[inline]
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:188:1
+ --> $DIR/naked-functions.rs:198:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:196:1
+ --> $DIR/naked-functions.rs:206:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:204:1
+ --> $DIR/naked-functions.rs:214:1
|
LL | #[inline]
| ^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:207:1
+ --> $DIR/naked-functions.rs:217:1
|
LL | #[inline(always)]
| ^^^^^^^^^^^^^^^^^
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
warning: naked functions cannot be inlined
- --> $DIR/naked-functions.rs:210:1
+ --> $DIR/naked-functions.rs:220:1
|
LL | #[inline(never)]
| ^^^^^^^^^^^^^^^^
// which causes less readable LLVM errors and in the worst cases causes ICEs
// or segfaults based on system dependent behavior and codegen flags.
-#![feature(asm, global_asm, naked_functions)]
+#![feature(asm, global_asm, naked_functions, asm_const)]
#[no_mangle]
pub static FOO: usize = 42;
// ignore-spirv
// ignore-wasm32
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
fn main() {
unsafe {
// only-x86_64
// compile-flags: -C target-feature=+avx2
-#![feature(asm)]
+#![feature(asm, asm_const, asm_sym)]
fn main() {
let mut foo = 0;
// revisions: mirunsafeck thirunsafeck
// [thirunsafeck]compile-flags: -Z thir-unsafeck
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
fn const_generic<const X: usize>() -> usize {
unsafe {
--- /dev/null
+// build-pass
+// only-x86_64
+
+#![feature(asm, target_feature_11)]
+
+#[target_feature(enable = "avx")]
+fn main() {
+ unsafe {
+ asm!(
+ "/* {} */",
+ out(ymm_reg) _,
+ );
+ }
+}
// only-x86_64
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
fn main() {
let mut foo = 0;
// only-linux
// run-pass
-#![feature(asm, thread_local)]
+#![feature(asm, thread_local, asm_sym)]
extern "C" fn f1() -> i32 {
111
std::thread::spawn(|| {
assert_eq!(static_addr!(S1), &S1 as *const u32);
assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
- }).join().unwrap();
+ })
+ .join()
+ .unwrap();
}
// only-x86_64
-#![feature(asm, repr_simd, never_type)]
+#![feature(asm, repr_simd, never_type, asm_sym)]
#[repr(simd)]
struct SimdNonCopy(f32, f32, f32, f32);
// only-x86_64
// compile-flags: -C target-feature=+avx512f
-#![feature(asm, global_asm)]
+#![feature(asm, global_asm, asm_const)]
use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps};
pub fn f1_uint_uint() {
f1(2u32, 4u32);
//~^ ERROR `u32: Foo` is not satisfied
+ //~| ERROR `u32: Foo` is not satisfied
}
pub fn f1_uint_int() {
f1(2u32, 4i32);
//~^ ERROR `u32: Foo` is not satisfied
+ //~| ERROR `u32: Foo` is not satisfied
}
pub fn f2_int() {
| ~~~
error[E0277]: the trait bound `u32: Foo` is not satisfied
- --> $DIR/associated-types-path-2.rs:29:14
+ --> $DIR/associated-types-path-2.rs:29:5
|
LL | f1(2u32, 4u32);
- | -- ^^^^ the trait `Foo` is not implemented for `u32`
- | |
- | required by a bound introduced by this call
+ | ^^ the trait `Foo` is not implemented for `u32`
|
note: required by a bound in `f1`
--> $DIR/associated-types-path-2.rs:13:14
| ^^^ required by this bound in `f1`
error[E0277]: the trait bound `u32: Foo` is not satisfied
- --> $DIR/associated-types-path-2.rs:34:14
+ --> $DIR/associated-types-path-2.rs:29:14
+ |
+LL | f1(2u32, 4u32);
+ | ^^^^ the trait `Foo` is not implemented for `u32`
+
+error[E0277]: the trait bound `u32: Foo` is not satisfied
+ --> $DIR/associated-types-path-2.rs:35:8
|
LL | f1(2u32, 4i32);
- | -- ^^^^ the trait `Foo` is not implemented for `u32`
+ | -- ^^^^ the trait `Foo` is not implemented for `u32`
| |
| required by a bound introduced by this call
|
LL | pub fn f1<T: Foo>(a: T, x: T::A) {}
| ^^^ required by this bound in `f1`
+error[E0277]: the trait bound `u32: Foo` is not satisfied
+ --> $DIR/associated-types-path-2.rs:35:14
+ |
+LL | f1(2u32, 4i32);
+ | ^^^^ the trait `Foo` is not implemented for `u32`
+
error[E0308]: mismatched types
- --> $DIR/associated-types-path-2.rs:39:18
+ --> $DIR/associated-types-path-2.rs:41:18
|
LL | let _: i32 = f2(2i32);
| --- ^^^^^^^^ expected `i32`, found `u32`
LL | let _: i32 = f2(2i32).try_into().unwrap();
| ++++++++++++++++++++
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+pub trait LineFormatter<'a> {
+ type Iter: Iterator<Item=&'a str> + 'a;
+ fn iter(&'a self, line: &'a str) -> Self::Iter;
+
+ fn dimensions(&'a self, line: &'a str) {
+ let iter: Self::Iter = self.iter(line);
+ <_ as IntoIterator>::into_iter(iter);
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+// Test transitive analysis for associated types. Collected types
+// should be normalized and new obligations generated.
+
+// pretty-expanded FIXME #23616
+
+trait Foo {
+ type A;
+ fn foo(&self) {}
+}
+
+impl Foo for usize {
+ type A = usize;
+}
+
+struct Bar<T: Foo> { inner: T::A }
+
+fn is_send<T: Send>() {}
+
+fn main() {
+ is_send::<Bar<usize>>();
+}
--- /dev/null
+// check-pass
+// Regression test for #28871. The problem is that rustc encountered
+// two ways to project, one from a where clause and one from the where
+// clauses on the trait definition. (In fact, in this case, the where
+// clauses originated from the trait definition as well.) The true
+// cause of the error is that the trait definition where clauses are
+// not being normalized, and hence the two sources are considered in
+// conflict, and not a duplicate. Hacky solution is to prefer where
+// clauses over the data found in the trait definition.
+
+trait T {
+ type T;
+}
+
+struct S;
+impl T for S {
+ type T = S;
+}
+
+trait T2 {
+ type T: Iterator<Item=<S as T>::T>;
+}
+
+fn main() { }
--- /dev/null
+// run-pass
+// Regression test for issue #47139:
+//
+// Coherence was encountering an (unnecessary) overflow trying to
+// decide if the two impls of dummy overlap.
+//
+// The overflow went something like:
+//
+// - `&'a ?T: Insertable` ?
+// - let ?T = Option<?U> ?
+// - `Option<?U>: Insertable` ?
+// - `Option<&'a ?U>: Insertable` ?
+// - `&'a ?U: Insertable` ?
+//
+// While somewhere in the middle, a projection would occur, which
+// broke cycle detection.
+//
+// It turned out that this cycle was being kicked off due to some
+// extended diagnostic attempts in coherence, so removing those
+// sidestepped the issue for now.
+
+#![allow(dead_code)]
+
+pub trait Insertable {
+ type Values;
+
+ fn values(self) -> Self::Values;
+}
+
+impl<T> Insertable for Option<T>
+ where
+ T: Insertable,
+ T::Values: Default,
+{
+ type Values = T::Values;
+
+ fn values(self) -> Self::Values {
+ self.map(Insertable::values).unwrap_or_default()
+ }
+}
+
+impl<'a, T> Insertable for &'a Option<T>
+ where
+ Option<&'a T>: Insertable,
+{
+ type Values = <Option<&'a T> as Insertable>::Values;
+
+ fn values(self) -> Self::Values {
+ self.as_ref().values()
+ }
+}
+
+impl<'a, T> Insertable for &'a [T]
+{
+ type Values = Self;
+
+ fn values(self) -> Self::Values {
+ self
+ }
+}
+
+trait Unimplemented { }
+
+trait Dummy { }
+
+struct Foo<T> { t: T }
+
+impl<'a, U> Dummy for Foo<&'a U>
+ where &'a U: Insertable
+{
+}
+
+impl<T> Dummy for T
+ where T: Unimplemented
+{ }
+
+fn main() {
+}
--- /dev/null
+// run-pass
+
+pub trait Stream {
+ type Item;
+ type Error;
+}
+
+pub trait ParseError<I> {
+ type Output;
+}
+
+impl ParseError<char> for u32 {
+ type Output = ();
+}
+
+impl Stream for () {
+ type Item = char;
+ type Error = u32;
+}
+
+pub struct Lex<'a, I>
+ where I: Stream,
+ I::Error: ParseError<char>,
+ <<I as Stream>::Error as ParseError<char>>::Output: 'a
+{
+ x: &'a <I::Error as ParseError<char>>::Output
+}
+
+pub struct Reserved<'a, I> where
+ I: Stream<Item=char> + 'a,
+ I::Error: ParseError<I::Item>,
+ <<I as Stream>::Error as ParseError<char>>::Output: 'a
+
+{
+ x: Lex<'a, I>
+}
+
+fn main() {
+ let r: Reserved<()> = Reserved {
+ x: Lex {
+ x: &()
+ }
+ };
+
+ let _v = r.x.x;
+}
error: future cannot be sent between threads safely
- --> $DIR/async-fn-nonsend.rs:49:5
+ --> $DIR/async-fn-nonsend.rs:49:17
|
LL | assert_send(local_dropped_before_await());
- | ^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
| ^^^^ required by this bound in `assert_send`
error: future cannot be sent between threads safely
- --> $DIR/async-fn-nonsend.rs:51:5
+ --> $DIR/async-fn-nonsend.rs:51:17
|
LL | assert_send(non_send_temporary_in_match());
- | ^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>`
note: future is not `Send` as this value is used across an await
| ^^^^ required by this bound in `assert_send`
error: future cannot be sent between threads safely
- --> $DIR/async-fn-nonsend.rs:53:5
+ --> $DIR/async-fn-nonsend.rs:53:17
|
LL | assert_send(non_sync_with_method_call());
- | ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
|
= help: the trait `Send` is not implemented for `dyn std::fmt::Write`
note: future is not `Send` as this value is used across an await
error: future cannot be shared between threads safely
- --> $DIR/issue-64130-1-sync.rs:21:5
+ --> $DIR/issue-64130-1-sync.rs:21:13
|
LL | is_sync(bar());
- | ^^^^^^^ future returned by `bar` is not `Sync`
+ | ^^^^^ future returned by `bar` is not `Sync`
|
= help: within `impl Future`, the trait `Sync` is not implemented for `Foo`
note: future is not `Sync` as this value is used across an await
error: future cannot be sent between threads safely
- --> $DIR/issue-64130-2-send.rs:21:5
+ --> $DIR/issue-64130-2-send.rs:21:13
|
LL | is_send(bar());
- | ^^^^^^^ future returned by `bar` is not `Send`
+ | ^^^^^ future returned by `bar` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `Foo`
note: future is not `Send` as this value is used across an await
error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future`
- --> $DIR/issue-64130-3-other.rs:24:5
+ --> $DIR/issue-64130-3-other.rs:24:12
|
LL | async fn bar() {
| - within this `impl Future`
...
LL | is_qux(bar());
- | ^^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo`
+ | ^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo`
|
note: future does not implement `Qux` as this value is used across an await
--> $DIR/issue-64130-3-other.rs:18:5
// edition:2018
+#![feature(must_not_suspend)]
+#![allow(must_not_suspend)]
// This tests the basic example case for the async-await-specific error.
error: future cannot be sent between threads safely
- --> $DIR/issue-64130-non-send-future-diags.rs:21:5
+ --> $DIR/issue-64130-non-send-future-diags.rs:23:13
|
LL | is_send(foo());
- | ^^^^^^^ future returned by `foo` is not `Send`
+ | ^^^^^ future returned by `foo` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, u32>`
note: future is not `Send` as this value is used across an await
- --> $DIR/issue-64130-non-send-future-diags.rs:15:5
+ --> $DIR/issue-64130-non-send-future-diags.rs:17:5
|
LL | let g = x.lock().unwrap();
| - has type `MutexGuard<'_, u32>` which is not `Send`
LL | }
| - `g` is later dropped here
note: required by a bound in `is_send`
- --> $DIR/issue-64130-non-send-future-diags.rs:7:15
+ --> $DIR/issue-64130-non-send-future-diags.rs:9:15
|
LL | fn is_send<T: Send>(t: T) { }
| ^^^^ required by this bound in `is_send`
// edition:2018
+#![feature(must_not_suspend)]
+#![allow(must_not_suspend)]
use std::future::Future;
use std::sync::Mutex;
error: future cannot be sent between threads safely
- --> $DIR/issue-71137.rs:20:3
+ --> $DIR/issue-71137.rs:22:14
|
LL | fake_spawn(wrong_mutex());
- | ^^^^^^^^^^ future returned by `wrong_mutex` is not `Send`
+ | ^^^^^^^^^^^^^ future returned by `wrong_mutex` is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, i32>`
note: future is not `Send` as this value is used across an await
- --> $DIR/issue-71137.rs:12:5
+ --> $DIR/issue-71137.rs:14:5
|
LL | let mut guard = m.lock().unwrap();
| --------- has type `MutexGuard<'_, i32>` which is not `Send`
LL | }
| - `mut guard` is later dropped here
note: required by a bound in `fake_spawn`
- --> $DIR/issue-71137.rs:6:27
+ --> $DIR/issue-71137.rs:8:27
|
LL | fn fake_spawn<F: Future + Send + 'static>(f: F) { }
| ^^^^ required by this bound in `fake_spawn`
--- /dev/null
+// edition:2018
+
+fn main() {
+ 'a: loop {
+ async {
+ loop {
+ continue 'a
+ //~^ ERROR use of unreachable label `'a`
+ }
+ };
+ }
+}
--- /dev/null
+error[E0767]: use of unreachable label `'a`
+ --> $DIR/issue-73541-1.rs:7:26
+ |
+LL | 'a: loop {
+ | -- unreachable label defined here
+...
+LL | continue 'a
+ | ^^ unreachable label `'a`
+ |
+ = note: labels are unreachable through functions, closures, async blocks and modules
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0767`.
fn main() {
g(issue_67893::run())
- //~^ ERROR: `MutexGuard<'_, ()>` cannot be sent between threads safely
+ //~^ ERROR generator cannot be sent between threads safely
}
-error[E0277]: `MutexGuard<'_, ()>` cannot be sent between threads safely
- --> $DIR/issue-67893.rs:9:5
+error: generator cannot be sent between threads safely
+ --> $DIR/issue-67893.rs:9:7
|
LL | g(issue_67893::run())
- | ^ `MutexGuard<'_, ()>` cannot be sent between threads safely
- |
- ::: $DIR/auxiliary/issue_67893.rs:7:20
- |
-LL | pub async fn run() {
- | - within this `impl Future`
+ | ^^^^^^^^^^^^^^^^^^ generator is not `Send`
|
= help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>`
- = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc<Mutex<()>>, &'r Mutex<()>, Result<MutexGuard<'s, ()>, PoisonError<MutexGuard<'t0, ()>>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}`
- = note: required because it appears within the type `[static generator@run::{closure#0}]`
- = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0}]>`
- = note: required because it appears within the type `impl Future`
- = note: required because it appears within the type `impl Future`
note: required by a bound in `g`
--> $DIR/issue-67893.rs:6:14
|
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0277`.
error[E0277]: `PhantomPinned` cannot be unpinned
- --> $DIR/pin-needed-to-poll-2.rs:43:9
+ --> $DIR/pin-needed-to-poll-2.rs:43:18
|
LL | Pin::new(&mut self.sleep).poll(cx)
- | ^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned`
+ | -------- ^^^^^^^^^^^^^^^ within `Sleep`, the trait `Unpin` is not implemented for `PhantomPinned`
+ | |
+ | required by a bound introduced by this call
|
= note: consider using `Box::pin`
note: required because it appears within the type `Sleep`
|
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
- = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+ = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
error: this attribute can only be applied at the crate level
--> $DIR/invalid-doc-attr.rs:15:12
|
= 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 #82730 <https://github.com/rust-lang/rust/issues/82730>
- = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#docno_inlinedocinline for more information
+ = note: read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information
error: aborting due to 6 previous errors
--- /dev/null
+// check-pass
+macro_rules! m {
+ ($i:meta) => {
+ #[derive($i)]
+ struct S;
+ }
+}
+
+m!(Clone);
+
+fn main() {}
let res =
::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""],
&match (&"u8",) {
- (arg0,) =>
- [::core::fmt::ArgumentV1::new(arg0,
+ _args =>
+ [::core::fmt::ArgumentV1::new(_args.0,
::core::fmt::Display::fmt)],
}));
res
--- /dev/null
+// build-pass (FIXME(62277): could be check-pass?)
+
+#![feature(rustc_attrs)]
+
+#[rustc_dummy(a b c d)]
+#[rustc_dummy[a b c d]]
+#[rustc_dummy{a b c d}]
+fn main() {}
+++ /dev/null
-#![crate_name = "a"]
-
-pub fn foo<T>() {}
+++ /dev/null
-#![crate_name = "a"]
-
-pub fn foo<T>() { println!("hello!"); }
+++ /dev/null
-#![crate_name = "b"]
-
-extern crate a;
-
-pub fn foo() { a::foo::<isize>(); }
+++ /dev/null
-#![feature(rustc_attrs)]
-
-#[rustc_legacy_const_generics(1)]
-pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
- [x, Y, z]
-}
+++ /dev/null
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-#[no_mangle]
-pub extern "C" fn foo() {}
+++ /dev/null
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-#[no_mangle]
-pub extern "C" fn foo() {}
+++ /dev/null
-// compile-flags: -Clinker-plugin-lto
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-pub fn foo() {}
+++ /dev/null
-// original problem
-pub fn foo<T>() -> isize {
- {
- static foo: isize = 2;
- foo
- }
-}
-
-// issue 8134
-struct Foo;
-impl Foo {
- pub fn foo<T>(&self) {
- static X: usize = 1;
- }
-}
-
-// issue 8134
-pub struct Parser<T>(T);
-impl<T: std::iter::Iterator<Item=char>> Parser<T> {
- fn in_doctype(&mut self) {
- static DOCTYPEPattern: [char; 6] = ['O', 'C', 'T', 'Y', 'P', 'E'];
- }
-}
-
-struct Bar;
-impl Foo {
- pub fn bar<T>(&self) {
- static X: usize = 1;
- }
-}
+++ /dev/null
-// check-pass
-
-// Bastion of the Turbofish
-// ------------------------
-// Beware travellers, lest you venture into waters callous and unforgiving,
-// where hope must be abandoned, ere it is cruelly torn from you. For here
-// stands the bastion of the Turbofish: an impenetrable fortress holding
-// unshaking against those who would dare suggest the supererogation of the
-// Turbofish.
-//
-// Once I was young and foolish and had the impudence to imagine that I could
-// shake free from the coils by which that creature had us tightly bound. I
-// dared to suggest that there was a better way: a brighter future, in which
-// Rustaceans both new and old could be rid of that vile beast. But alas! In
-// my foolhardiness my ignorance was unveiled and my dreams were dashed
-// unforgivingly against the rock of syntactic ambiguity.
-//
-// This humble program, small and insignificant though it might seem,
-// demonstrates that to which we had previously cast a blind eye: an ambiguity
-// in permitting generic arguments to be provided without the consent of the
-// Great Turbofish. Should you be so naïve as to try to revolt against its
-// mighty clutches, here shall its wrath be indomitably displayed. This
-// program must pass for all eternity: forever watched by the guardian angel
-// which gave this beast its name, and stands fundamentally at odds with the
-// impetuous rebellion against the Turbofish.
-//
-// My heart aches in sorrow, for I know I am defeated. Let this be a warning
-// to all those who come after: for they too must overcome the impassible
-// hurdle of defeating the great beast, championed by a resolute winged
-// guardian.
-//
-// Here stands the Bastion of the Turbofish, a memorial to Anna Harren,
-// Guardian Angel of these Hallowed Grounds. <3
-
-// See https://github.com/rust-lang/rust/pull/53562
-// and https://github.com/rust-lang/rfcs/pull/2527
-// and https://twitter.com/garblefart/status/1393236602856611843
-// for context.
-
-fn main() {
- let (the, guardian, stands, resolute) = ("the", "Turbofish", "remains", "undefeated");
- let _: (bool, bool) = (the<guardian, stands>(resolute));
-}
-error[E0659]: `f` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `f` is ambiguous
--> $DIR/ambiguity-item.rs:14:13
|
LL | let v = f;
| ^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `f` could refer to the function imported here
--> $DIR/ambiguity-item.rs:6:5
|
| ^^^^
= help: consider adding an explicit import of `f` to disambiguate
-error[E0659]: `f` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `f` is ambiguous
--> $DIR/ambiguity-item.rs:16:9
|
LL | f => {}
| ^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `f` could refer to the function imported here
--> $DIR/ambiguity-item.rs:6:5
|
--- /dev/null
+// run-pass
+
+#![allow(non_camel_case_types)]
+
+
+#[derive(Copy, Clone, Debug)]
+enum foo { large, small, }
+
+impl PartialEq for foo {
+ fn eq(&self, other: &foo) -> bool {
+ ((*self) as usize) == ((*other) as usize)
+ }
+ fn ne(&self, other: &foo) -> bool { !(*self).eq(other) }
+}
+
+pub fn main() {
+ let a = (1, 2, 3);
+ let b = (1, 2, 3);
+ assert_eq!(a, b);
+ assert!((a != (1, 2, 4)));
+ assert!((a < (1, 2, 4)));
+ assert!((a <= (1, 2, 4)));
+ assert!(((1, 2, 4) > a));
+ assert!(((1, 2, 4) >= a));
+ let x = foo::large;
+ let y = foo::small;
+ assert!((x != y));
+ assert_eq!(x, foo::large);
+ assert!((x != foo::small));
+}
--- /dev/null
+// run-pass
+struct A;
+
+impl A {
+ fn take_mutably(&mut self) {}
+}
+
+fn identity<T>(t: T) -> T {
+ t
+}
+
+// Issue 46095
+// Built-in indexing should be used even when the index is not
+// trivially an integer
+// Overloaded indexing would cause wrapped to be borrowed mutably
+
+fn main() {
+ let mut a1 = A;
+ let mut a2 = A;
+
+ let wrapped = [&mut a1, &mut a2];
+
+ {
+ wrapped[0 + 1 - 1].take_mutably();
+ }
+
+ {
+ wrapped[identity(0)].take_mutably();
+ }
+}
--- /dev/null
+// run-pass
+
+fn f(x: Box<isize>) {
+ let y: &isize = &*x;
+ println!("{}", *x);
+ println!("{}", *y);
+}
+
+trait Trait {
+ fn printme(&self);
+}
+
+struct Struct;
+
+impl Trait for Struct {
+ fn printme(&self) {
+ println!("hello world!");
+ }
+}
+
+fn g(x: Box<dyn Trait>) {
+ x.printme();
+ let y: &dyn Trait = &*x;
+ y.printme();
+}
+
+fn main() {
+ f(Box::new(1234));
+ g(Box::new(Struct) as Box<dyn Trait>);
+}
--- /dev/null
+extern "C" {
+ fn foo(a: i32, ...);
+}
+
+fn bar(_: *const u8) {}
+
+fn main() {
+ unsafe {
+ foo(0, bar);
+ //~^ ERROR can't pass `fn(*const u8) {bar}` to variadic function
+ //~| HELP cast the value to `fn(*const u8)`
+ }
+}
--- /dev/null
+error[E0617]: can't pass `fn(*const u8) {bar}` to variadic function
+ --> $DIR/issue-32201.rs:9:16
+ |
+LL | foo(0, bar);
+ | ^^^ help: cast the value to `fn(*const u8)`: `bar as fn(*const u8)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0617`.
--- /dev/null
+// run-pass
+
+pub fn main() {
+ let f = 1_usize as *const String;
+ println!("{:?}", f as isize);
+ println!("{:?}", f as usize);
+ println!("{:?}", f as i8);
+ println!("{:?}", f as i16);
+ println!("{:?}", f as i32);
+ println!("{:?}", f as i64);
+ println!("{:?}", f as u8);
+ println!("{:?}", f as u16);
+ println!("{:?}", f as u32);
+ println!("{:?}", f as u64);
+
+ println!("{:?}", 1 as isize);
+ println!("{:?}", 1 as usize);
+ println!("{:?}", 1 as *const String);
+ println!("{:?}", 1 as i8);
+ println!("{:?}", 1 as i16);
+ println!("{:?}", 1 as i32);
+ println!("{:?}", 1 as i64);
+ println!("{:?}", 1 as u8);
+ println!("{:?}", 1 as u16);
+ println!("{:?}", 1 as u32);
+ println!("{:?}", 1 as u64);
+ println!("{:?}", 1 as f32);
+ println!("{:?}", 1 as f64);
+
+ println!("{:?}", 1_usize as isize);
+ println!("{:?}", 1_usize as usize);
+ println!("{:?}", 1_usize as *const String);
+ println!("{:?}", 1_usize as i8);
+ println!("{:?}", 1_usize as i16);
+ println!("{:?}", 1_usize as i32);
+ println!("{:?}", 1_usize as i64);
+ println!("{:?}", 1_usize as u8);
+ println!("{:?}", 1_usize as u16);
+ println!("{:?}", 1_usize as u32);
+ println!("{:?}", 1_usize as u64);
+ println!("{:?}", 1_usize as f32);
+ println!("{:?}", 1_usize as f64);
+
+ println!("{:?}", 1i8 as isize);
+ println!("{:?}", 1i8 as usize);
+ println!("{:?}", 1i8 as *const String);
+ println!("{:?}", 1i8 as i8);
+ println!("{:?}", 1i8 as i16);
+ println!("{:?}", 1i8 as i32);
+ println!("{:?}", 1i8 as i64);
+ println!("{:?}", 1i8 as u8);
+ println!("{:?}", 1i8 as u16);
+ println!("{:?}", 1i8 as u32);
+ println!("{:?}", 1i8 as u64);
+ println!("{:?}", 1i8 as f32);
+ println!("{:?}", 1i8 as f64);
+
+ println!("{:?}", 1u8 as isize);
+ println!("{:?}", 1u8 as usize);
+ println!("{:?}", 1u8 as *const String);
+ println!("{:?}", 1u8 as i8);
+ println!("{:?}", 1u8 as i16);
+ println!("{:?}", 1u8 as i32);
+ println!("{:?}", 1u8 as i64);
+ println!("{:?}", 1u8 as u8);
+ println!("{:?}", 1u8 as u16);
+ println!("{:?}", 1u8 as u32);
+ println!("{:?}", 1u8 as u64);
+ println!("{:?}", 1u8 as f32);
+ println!("{:?}", 1u8 as f64);
+
+ println!("{:?}", 1i16 as isize);
+ println!("{:?}", 1i16 as usize);
+ println!("{:?}", 1i16 as *const String);
+ println!("{:?}", 1i16 as i8);
+ println!("{:?}", 1i16 as i16);
+ println!("{:?}", 1i16 as i32);
+ println!("{:?}", 1i16 as i64);
+ println!("{:?}", 1i16 as u8);
+ println!("{:?}", 1i16 as u16);
+ println!("{:?}", 1i16 as u32);
+ println!("{:?}", 1i16 as u64);
+ println!("{:?}", 1i16 as f32);
+ println!("{:?}", 1i16 as f64);
+
+ println!("{:?}", 1u16 as isize);
+ println!("{:?}", 1u16 as usize);
+ println!("{:?}", 1u16 as *const String);
+ println!("{:?}", 1u16 as i8);
+ println!("{:?}", 1u16 as i16);
+ println!("{:?}", 1u16 as i32);
+ println!("{:?}", 1u16 as i64);
+ println!("{:?}", 1u16 as u8);
+ println!("{:?}", 1u16 as u16);
+ println!("{:?}", 1u16 as u32);
+ println!("{:?}", 1u16 as u64);
+ println!("{:?}", 1u16 as f32);
+ println!("{:?}", 1u16 as f64);
+
+ println!("{:?}", 1i32 as isize);
+ println!("{:?}", 1i32 as usize);
+ println!("{:?}", 1i32 as *const String);
+ println!("{:?}", 1i32 as i8);
+ println!("{:?}", 1i32 as i16);
+ println!("{:?}", 1i32 as i32);
+ println!("{:?}", 1i32 as i64);
+ println!("{:?}", 1i32 as u8);
+ println!("{:?}", 1i32 as u16);
+ println!("{:?}", 1i32 as u32);
+ println!("{:?}", 1i32 as u64);
+ println!("{:?}", 1i32 as f32);
+ println!("{:?}", 1i32 as f64);
+
+ println!("{:?}", 1u32 as isize);
+ println!("{:?}", 1u32 as usize);
+ println!("{:?}", 1u32 as *const String);
+ println!("{:?}", 1u32 as i8);
+ println!("{:?}", 1u32 as i16);
+ println!("{:?}", 1u32 as i32);
+ println!("{:?}", 1u32 as i64);
+ println!("{:?}", 1u32 as u8);
+ println!("{:?}", 1u32 as u16);
+ println!("{:?}", 1u32 as u32);
+ println!("{:?}", 1u32 as u64);
+ println!("{:?}", 1u32 as f32);
+ println!("{:?}", 1u32 as f64);
+
+ println!("{:?}", 1i64 as isize);
+ println!("{:?}", 1i64 as usize);
+ println!("{:?}", 1i64 as *const String);
+ println!("{:?}", 1i64 as i8);
+ println!("{:?}", 1i64 as i16);
+ println!("{:?}", 1i64 as i32);
+ println!("{:?}", 1i64 as i64);
+ println!("{:?}", 1i64 as u8);
+ println!("{:?}", 1i64 as u16);
+ println!("{:?}", 1i64 as u32);
+ println!("{:?}", 1i64 as u64);
+ println!("{:?}", 1i64 as f32);
+ println!("{:?}", 1i64 as f64);
+
+ println!("{:?}", 1u64 as isize);
+ println!("{:?}", 1u64 as usize);
+ println!("{:?}", 1u64 as *const String);
+ println!("{:?}", 1u64 as i8);
+ println!("{:?}", 1u64 as i16);
+ println!("{:?}", 1u64 as i32);
+ println!("{:?}", 1u64 as i64);
+ println!("{:?}", 1u64 as u8);
+ println!("{:?}", 1u64 as u16);
+ println!("{:?}", 1u64 as u32);
+ println!("{:?}", 1u64 as u64);
+ println!("{:?}", 1u64 as f32);
+ println!("{:?}", 1u64 as f64);
+
+ println!("{:?}", 1u64 as isize);
+ println!("{:?}", 1u64 as usize);
+ println!("{:?}", 1u64 as *const String);
+ println!("{:?}", 1u64 as i8);
+ println!("{:?}", 1u64 as i16);
+ println!("{:?}", 1u64 as i32);
+ println!("{:?}", 1u64 as i64);
+ println!("{:?}", 1u64 as u8);
+ println!("{:?}", 1u64 as u16);
+ println!("{:?}", 1u64 as u32);
+ println!("{:?}", 1u64 as u64);
+ println!("{:?}", 1u64 as f32);
+ println!("{:?}", 1u64 as f64);
+
+ println!("{:?}", true as isize);
+ println!("{:?}", true as usize);
+ println!("{:?}", true as i8);
+ println!("{:?}", true as i16);
+ println!("{:?}", true as i32);
+ println!("{:?}", true as i64);
+ println!("{:?}", true as u8);
+ println!("{:?}", true as u16);
+ println!("{:?}", true as u32);
+ println!("{:?}", true as u64);
+
+ println!("{:?}", 1f32 as isize);
+ println!("{:?}", 1f32 as usize);
+ println!("{:?}", 1f32 as i8);
+ println!("{:?}", 1f32 as i16);
+ println!("{:?}", 1f32 as i32);
+ println!("{:?}", 1f32 as i64);
+ println!("{:?}", 1f32 as u8);
+ println!("{:?}", 1f32 as u16);
+ println!("{:?}", 1f32 as u32);
+ println!("{:?}", 1f32 as u64);
+ println!("{:?}", 1f32 as f32);
+ println!("{:?}", 1f32 as f64);
+
+ println!("{:?}", 1f64 as isize);
+ println!("{:?}", 1f64 as usize);
+ println!("{:?}", 1f64 as i8);
+ println!("{:?}", 1f64 as i16);
+ println!("{:?}", 1f64 as i32);
+ println!("{:?}", 1f64 as i64);
+ println!("{:?}", 1f64 as u8);
+ println!("{:?}", 1f64 as u16);
+ println!("{:?}", 1f64 as u32);
+ println!("{:?}", 1f64 as u64);
+ println!("{:?}", 1f64 as f32);
+ println!("{:?}", 1f64 as f64);
+}
+++ /dev/null
-// ignore-msvc FIXME #31306
-
-// note that these aux-build directives must be in this order
-// aux-build:changing-crates-a1.rs
-// aux-build:changing-crates-b.rs
-// aux-build:changing-crates-a2.rs
-// normalize-stderr-test: "(crate `(\w+)`:) .*" -> "$1 $$PATH_$2"
-
-extern crate a;
-extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on
-
-fn main() {}
+++ /dev/null
-error[E0460]: found possibly newer version of crate `a` which `b` depends on
- --> $DIR/changing-crates.rs:10:1
- |
-LL | extern crate b;
- | ^^^^^^^^^^^^^^^
- |
- = note: perhaps that crate needs to be recompiled?
- = note: the following crate versions were found:
- crate `a`: $PATH_a
- crate `b`: $PATH_b
-
-error: aborting due to previous error
-
--- /dev/null
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE lint level is defined here
+
+fn main() {
+ struct Foo(u32);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("dropped {}", self.0);
+ }
+ }
+
+ let f0 = Foo(0);
+ let f1 = Foo(1);
+
+ let c0 = move || {
+ let _ = &f0;
+ //~^ ERROR changes to closure capture in Rust 2021 will affect drop order
+ //~| NOTE for more information
+ let _ = f0;
+ //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect
+ };
+
+ let c1 = move || {
+ let _ = &f1;
+ };
+
+ println!("dropping 0");
+ drop(c0);
+ println!("dropping 1");
+ drop(c1);
+ println!("dropped all");
+}
+//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure
--- /dev/null
+// run-rustfix
+
+#![deny(rust_2021_incompatible_closure_captures)]
+//~^ NOTE lint level is defined here
+
+fn main() {
+ struct Foo(u32);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("dropped {}", self.0);
+ }
+ }
+
+ let f0 = Foo(0);
+ let f1 = Foo(1);
+
+ let c0 = move || {
+ //~^ ERROR changes to closure capture in Rust 2021 will affect drop order
+ //~| NOTE for more information
+ let _ = f0;
+ //~^ NOTE in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect
+ };
+
+ let c1 = move || {
+ let _ = &f1;
+ };
+
+ println!("dropping 0");
+ drop(c0);
+ println!("dropping 1");
+ drop(c1);
+ println!("dropped all");
+}
+//~^ NOTE in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure
--- /dev/null
+error: changes to closure capture in Rust 2021 will affect drop order
+ --> $DIR/issue-90465.rs:17:14
+ |
+LL | let c0 = move || {
+ | ^^^^^^^
+...
+LL | let _ = f0;
+ | -- in Rust 2018, this causes the closure to capture `f0`, but in Rust 2021, it has no effect
+...
+LL | }
+ | - in Rust 2018, `f0` is dropped here along with the closure, but in Rust 2021 `f0` is not part of the closure
+ |
+note: the lint level is defined here
+ --> $DIR/issue-90465.rs:3:9
+ |
+LL | #![deny(rust_2021_incompatible_closure_captures)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `f0` to be fully captured
+ |
+LL ~ let c0 = move || {
+LL + let _ = &f0;
+ |
+
+error: aborting due to previous error
+
let mut f = 10;
let fptr = SendPointer(&mut f as *mut i32);
thread::spawn(move || { let _ = &fptr; unsafe {
- //~^ ERROR: `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr` to be fully captured
*fptr.0 = 20;
let f = CustomInt(&mut f as *mut i32);
let fptr = SyncPointer(f);
thread::spawn(move || { let _ = &fptr; unsafe {
- //~^ ERROR: `Sync`, `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr` to be fully captured
*fptr.0.0 = 20;
let f = U(S(Foo(0)), T(0));
let c = || {
let _ = &f;
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f` to be fully captured
let f_1 = f.1;
let mut f = 10;
let fptr = SendPointer(&mut f as *mut i32);
thread::spawn(move || unsafe {
- //~^ ERROR: `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr` to be fully captured
*fptr.0 = 20;
let f = CustomInt(&mut f as *mut i32);
let fptr = SyncPointer(f);
thread::spawn(move || unsafe {
- //~^ ERROR: `Sync`, `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
+ //~^ ERROR: changes to closure capture
+ //~| NOTE: in Rust 2018, this closure implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr` to be fully captured
*fptr.0.0 = 20;
fn test_clone_trait() {
let f = U(S(Foo(0)), T(0));
let c = || {
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f` to be fully captured
let f_1 = f.1;
-error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
--> $DIR/auto_traits.rs:22:19
|
LL | thread::spawn(move || unsafe {
- | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
+ | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0` does not implement `Send`
...
LL | *fptr.0 = 20;
| ------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0`
LL | *fptr.0 = 20;
...
-error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
--> $DIR/auto_traits.rs:42:19
|
LL | thread::spawn(move || unsafe {
- | ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
+ | ^^^^^^^^^^^^^^
+ | |
+ | in Rust 2018, this closure implements `Sync` as `fptr` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr` is not fully captured and `fptr.0.0` does not implement `Sync`
+ | in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr` is not fully captured and `fptr.0.0` does not implement `Send`
...
LL | *fptr.0.0 = 20;
| --------- in Rust 2018, this closure captures all of `fptr`, but in Rust 2021, it will only capture `fptr.0.0`
LL |
LL |
LL |
-LL | *fptr.0.0 = 20;
+LL |
...
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
- --> $DIR/auto_traits.rs:66:13
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ --> $DIR/auto_traits.rs:67:13
|
LL | let c = || {
- | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
+ | ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f` is not fully captured and `f.1` does not implement `Clone`
...
LL | let f_1 = f.1;
| --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.1`
--- /dev/null
+// Test that rustc doesn't ICE as in #90024.
+// check-pass
+// edition=2018
+
+#![warn(rust_2021_incompatible_closure_captures)]
+
+// Checks there's no double-subst into the generic args, otherwise we get OOB
+// MCVE by @lqd
+pub struct Graph<N, E, Ix> {
+ _edges: E,
+ _nodes: N,
+ _ix: Vec<Ix>,
+}
+fn graph<N, E>() -> Graph<N, E, i32> {
+ todo!()
+}
+fn first_ice() {
+ let g = graph::<i32, i32>();
+ let _ = || g;
+}
+
+// Checks that there is a subst into the fields, otherwise we get normalization error
+// MCVE by @cuviper
+use std::iter::Empty;
+struct Foo<I: Iterator> {
+ data: Vec<I::Item>,
+}
+pub fn second_ice() {
+ let v = Foo::<Empty<()>> { data: vec![] };
+
+ (|| v.data[0])();
+}
+
+pub fn main() {
+ first_ice();
+ second_ice();
+}
let f = panic::AssertUnwindSafe(f);
let result = panic::catch_unwind(move || {
let _ = &f;
- //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`
+ //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f` to be fully captured
f.0()
{
let f = panic::AssertUnwindSafe(f);
let result = panic::catch_unwind(move || {
- //~^ ERROR: `UnwindSafe`, `RefUnwindSafe` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `UnwindSafe`
+ //~| NOTE: in Rust 2018, this closure implements `RefUnwindSafe`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f` to be fully captured
f.0()
-error: changes to closure capture in Rust 2021 will affect `UnwindSafe`, `RefUnwindSafe` trait implementation for closure
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
--> $DIR/mir_calls_to_shims.rs:20:38
|
LL | let result = panic::catch_unwind(move || {
- | ^^^^^^^ in Rust 2018, this closure implements `UnwindSafe`, `RefUnwindSafe` as `f` implements `UnwindSafe`, `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe`, `RefUnwindSafe` as `f.0` does not implement `UnwindSafe`, `RefUnwindSafe`
+ | ^^^^^^^
+ | |
+ | in Rust 2018, this closure implements `UnwindSafe` as `f` implements `UnwindSafe`, but in Rust 2021, this closure will no longer implement `UnwindSafe` because `f` is not fully captured and `f.0` does not implement `UnwindSafe`
+ | in Rust 2018, this closure implements `RefUnwindSafe` as `f` implements `RefUnwindSafe`, but in Rust 2021, this closure will no longer implement `RefUnwindSafe` because `f` is not fully captured and `f.0` does not implement `RefUnwindSafe`
...
LL | f.0()
| --- in Rust 2018, this closure captures all of `f`, but in Rust 2021, it will only capture `f.0`
}
}
-
struct S(Foo);
#[derive(Clone)]
let f2 = U(S(Foo::from("bar")), T(0));
let c = || {
let _ = (&f1, &f2);
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured
let _f_1 = f1.0;
let f1 = U(S(Foo::from("foo")), T(0));
let c = || {
let _ = &f1;
- //~^ ERROR: `Clone` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_1 = f1.0;
let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
let _ = &f1;
- //~^ ERROR: `Clone` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_0 = f1.0;
let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
let _ = &f1;
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_0 = f1.0;
let mut f2 = 10;
let fptr2 = SendPointer(&mut f2 as *mut i32);
thread::spawn(move || { let _ = (&fptr1, &fptr2); unsafe {
- //~^ ERROR: `Sync`, `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send`
- //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send`
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured
*fptr1.0.0 = 20;
}
}
-
struct S(Foo);
#[derive(Clone)]
let f1 = U(S(Foo::from("foo")), T(0));
let f2 = U(S(Foo::from("bar")), T(0));
let c = || {
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1`, `f2` to be fully captured
let _f_1 = f1.0;
fn test_capturing_all_disjoint_fields_individually() {
let f1 = U(S(Foo::from("foo")), T(0));
let c = || {
- //~^ ERROR: `Clone` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_1 = f1.0;
fn test_capturing_several_disjoint_fields_individually_1() {
let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
- //~^ ERROR: `Clone` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect which traits the closure implements [rust_2021_incompatible_closure_captures]
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_0 = f1.0;
fn test_capturing_several_disjoint_fields_individually_2() {
let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
let c = || {
- //~^ ERROR: `Clone` trait implementation for closure and drop order
- //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ //~^ ERROR: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `f1` to be fully captured
let _f_0 = f1.0;
let mut f2 = 10;
let fptr2 = SendPointer(&mut f2 as *mut i32);
thread::spawn(move || unsafe {
- //~^ ERROR: `Sync`, `Send` trait implementation for closure
- //~| NOTE: in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send`
- //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send`
+ //~^ ERROR: changes to closure capture in Rust 2021
+ //~| NOTE: in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`
+ //~| NOTE: in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`
//~| NOTE: for more information, see
//~| HELP: add a dummy let to cause `fptr1`, `fptr2` to be fully captured
*fptr1.0.0 = 20;
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
- --> $DIR/multi_diagnostics.rs:38:13
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:37:13
|
LL | let c = || {
- | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
...
LL | let _f_1 = f1.0;
| ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
LL + let _ = (&f1, &f2);
|
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
- --> $DIR/multi_diagnostics.rs:57:13
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:56:13
|
LL | let c = || {
- | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
...
LL | let _f_1 = f1.0;
| ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
LL + let _ = &f1;
|
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
- --> $DIR/multi_diagnostics.rs:82:13
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:81:13
|
LL | let c = || {
| ^^
| |
- | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
- | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.2` does not implement `Clone`
+ | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
+ | in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.2` does not implement `Clone`
...
LL | let _f_0 = f1.0;
| ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
LL + let _ = &f1;
|
-error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
- --> $DIR/multi_diagnostics.rs:101:13
+error: changes to closure capture in Rust 2021 will affect drop order and which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:100:13
|
LL | let c = || {
- | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
+ | ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` because `f1` is not fully captured and `f1.0` does not implement `Clone`
...
LL | let _f_0 = f1.0;
| ---- in Rust 2018, this closure captures all of `f1`, but in Rust 2021, it will only capture `f1.0`
LL + let _ = &f1;
|
-error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
- --> $DIR/multi_diagnostics.rs:134:19
+error: changes to closure capture in Rust 2021 will affect which traits the closure implements
+ --> $DIR/multi_diagnostics.rs:133:19
|
LL | thread::spawn(move || unsafe {
| ^^^^^^^^^^^^^^
| |
- | in Rust 2018, this closure implements `Sync`, `Send` as `fptr1` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr1.0.0` does not implement `Sync`, `Send`
- | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr2.0` does not implement `Send`
+ | in Rust 2018, this closure implements `Sync` as `fptr1` implements `Sync`, but in Rust 2021, this closure will no longer implement `Sync` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Sync`
+ | in Rust 2018, this closure implements `Send` as `fptr1` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr1` is not fully captured and `fptr1.0.0` does not implement `Send`
+ | in Rust 2018, this closure implements `Send` as `fptr2` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` because `fptr2` is not fully captured and `fptr2.0` does not implement `Send`
...
LL | *fptr1.0.0 = 20;
| ---------- in Rust 2018, this closure captures all of `fptr1`, but in Rust 2021, it will only capture `fptr1.0.0`
--- /dev/null
+#![feature(box_syntax)]
+
+fn main() {
+ let x: Box<_> = box 1;
+ let f = move|| {
+ let _a = x;
+ drop(x);
+ //~^ ERROR: use of moved value: `x`
+ };
+ f();
+}
--- /dev/null
+error[E0382]: use of moved value: `x`
+ --> $DIR/issue-10398.rs:7:14
+ |
+LL | let _a = x;
+ | - value moved here
+LL | drop(x);
+ | ^ value used here after move
+ |
+ = note: move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+// run-pass
+use std::ops::{Deref, DerefMut};
+
+struct CheckedDeref<T, F> {
+ value: T,
+ check: F
+}
+
+impl<F: Fn(&T) -> bool, T> Deref for CheckedDeref<T, F> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ assert!((self.check)(&self.value));
+ &self.value
+ }
+}
+
+impl<F: Fn(&T) -> bool, T> DerefMut for CheckedDeref<T, F> {
+ fn deref_mut(&mut self) -> &mut T {
+ assert!((self.check)(&self.value));
+ &mut self.value
+ }
+}
+
+
+fn main() {
+ let mut v = CheckedDeref {
+ value: vec![0],
+ check: |v: &Vec<_>| !v.is_empty()
+ };
+ v.push(1);
+ assert_eq!(*v, vec![0, 1]);
+}
| expected due to this
|
= note: expected unit type `()`
- found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable)]`
+ found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#22t, extern "rust-call" fn(()), _#23t]]`
help: use parentheses to call this closure
|
LL | let c1 : () = c();
| expected due to this
|
= note: expected unit type `()`
- found closure `[f<T>::{closure#0} closure_substs=(unavailable)]`
+ found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#22t, extern "rust-call" fn(()), _#23t]]`
help: use parentheses to call this closure
|
LL | let c1 : () = c();
| expected due to this
|
= note: expected fn pointer `fn(u8) -> u8`
- found closure `[main::{closure#0} closure_substs=(unavailable)]`
+ found closure `[main::{closure#0} closure_substs=(unavailable) substs=[i8, extern "rust-call" fn((u8,)) -> u8, _#6t]]`
note: closures can only be coerced to `fn` types if they do not capture any variables
--> $DIR/closure-print-verbose.rs:10:39
|
--- /dev/null
+#![crate_type="rlib"]
+
+#[derive(Debug, PartialEq)]
+pub struct RemoteC(pub u32);
+
+#[derive(Debug, PartialEq)]
+pub struct RemoteG<T>(pub T);
--- /dev/null
+// run-pass
+// All 3 expressions should work in that the argument gets
+// coerced to a trait object
+
+// pretty-expanded FIXME #23616
+
+fn main() {
+ send::<Box<dyn Foo>>(Box::new(Output(0)));
+ Test::<Box<dyn Foo>>::foo(Box::new(Output(0)));
+ Test::<Box<dyn Foo>>::new().send(Box::new(Output(0)));
+}
+
+fn send<T>(_: T) {}
+
+struct Test<T> { marker: std::marker::PhantomData<T> }
+impl<T> Test<T> {
+ fn new() -> Test<T> { Test { marker: ::std::marker::PhantomData } }
+ fn foo(_: T) {}
+ fn send(&self, _: T) {}
+}
+
+trait Foo { fn dummy(&self) { }}
+struct Output(isize);
+impl Foo for Output {}
--- /dev/null
+// run-pass
+// aux-build:issue-39823.rs
+
+extern crate issue_39823;
+use issue_39823::{RemoteC, RemoteG};
+
+#[derive(Debug, PartialEq)]
+struct LocalC(u32);
+
+#[derive(Debug, PartialEq)]
+struct LocalG<T>(T);
+
+fn main() {
+ let virtual_localc : &dyn Fn(_) -> LocalC = &LocalC;
+ assert_eq!(virtual_localc(1), LocalC(1));
+
+ let virtual_localg : &dyn Fn(_) -> LocalG<u32> = &LocalG;
+ assert_eq!(virtual_localg(1), LocalG(1));
+
+ let virtual_remotec : &dyn Fn(_) -> RemoteC = &RemoteC;
+ assert_eq!(virtual_remotec(1), RemoteC(1));
+
+ let virtual_remoteg : &dyn Fn(_) -> RemoteG<u32> = &RemoteG;
+ assert_eq!(virtual_remoteg(1), RemoteG(1));
+}
--- /dev/null
+fn main() {
+ let _ = &&[0] as &[_];
+ //~^ ERROR non-primitive cast: `&&[i32; 1]` as `&[_]`
+ let _ = 7u32 as Option<_>;
+ //~^ ERROR non-primitive cast: `u32` as `Option<_>`
+}
--- /dev/null
+error[E0605]: non-primitive cast: `&&[i32; 1]` as `&[_]`
+ --> $DIR/issue-73886.rs:2:13
+ |
+LL | let _ = &&[0] as &[_];
+ | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error[E0605]: non-primitive cast: `u32` as `Option<_>`
+ --> $DIR/issue-73886.rs:4:13
+ |
+LL | let _ = 7u32 as Option<_>;
+ | ^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `Option<_>::from(7u32)`
+ |
+ = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0605`.
--- /dev/null
+pub struct A;
+impl From<fn((), (), &())> for A {
+ fn from(_: fn((), (), &mut ())) -> Self {
+ //~^ error: method `from` has an incompatible type for trait
+ loop {}
+ }
+}
+
+pub struct B;
+impl From<fn((), (), u32)> for B {
+ fn from(_: fn((), (), u64)) -> Self {
+ //~^ error: method `from` has an incompatible type for trait
+ loop {}
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0053]: method `from` has an incompatible type for trait
+ --> $DIR/issue-90444.rs:3:16
+ |
+LL | fn from(_: fn((), (), &mut ())) -> Self {
+ | ^^^^^^^^^^^^^^^^^^^
+ | |
+ | types differ in mutability
+ | help: change the parameter type to match the trait: `for<'r> fn((), (), &'r ())`
+ |
+ = note: expected fn pointer `fn(for<'r> fn((), (), &'r ())) -> A`
+ found fn pointer `fn(for<'r> fn((), (), &'r mut ())) -> A`
+
+error[E0053]: method `from` has an incompatible type for trait
+ --> $DIR/issue-90444.rs:11:16
+ |
+LL | fn from(_: fn((), (), u64)) -> Self {
+ | ^^^^^^^^^^^^^^^
+ | |
+ | expected `u32`, found `u64`
+ | help: change the parameter type to match the trait: `fn((), (), u32)`
+ |
+ = note: expected fn pointer `fn(fn((), (), u32)) -> B`
+ found fn pointer `fn(fn((), (), u64)) -> B`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0053`.
--- /dev/null
+// check-pass
+
+macro_rules! m {
+ () => { #[cfg(any())] fn f() {} }
+}
+
+trait T {}
+impl T for () { m!(); }
+
+fn main() {}
--- /dev/null
+#![feature(rustc_attrs)]
+
+#[rustc_legacy_const_generics(1)]
+pub fn foo<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
+ [x, Y, z]
+}
--- /dev/null
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(unused_braces, incomplete_features)]
+
+pub trait Foo<const N: usize> {}
+pub trait Bar: Foo<{ 1 }> { }
+
+fn main() {}
error[E0277]: the trait bound `(): _Contains<&C>` is not satisfied
- --> $DIR/issue-85848.rs:24:5
+ --> $DIR/issue-85848.rs:24:29
|
LL | writes_to_specific_path(&cap);
- | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `_Contains<&C>` is not implemented for `()`
+ | ----------------------- ^^^^ the trait `_Contains<&C>` is not implemented for `()`
+ | |
+ | required by a bound introduced by this call
|
note: required because of the requirements on the impl of `Contains<(), true>` for `&C`
--> $DIR/issue-85848.rs:21:12
| ^^^^^^^^^^^^^ required by this bound in `writes_to_specific_path`
error: unconstrained generic constant
- --> $DIR/issue-85848.rs:24:5
+ --> $DIR/issue-85848.rs:24:29
|
LL | writes_to_specific_path(&cap);
- | ^^^^^^^^^^^^^^^^^^^^^^^
+ | ----------------------- ^^^^
+ | |
+ | required by a bound introduced by this call
|
= help: try adding a `where` bound using this expression: `where [(); { contains::<T, U>() }]:`
note: required because of the requirements on the impl of `Contains<(), true>` for `&C`
|
LL | assert_eq!(f::<4usize>(Usizable), 20usize);
| ^^^^^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+struct ConstAssert<const COND: bool>;
+trait True {}
+impl True for ConstAssert<true> {}
+
+struct Range<T: PartialOrd, const MIN: T, const MAX: T>(T)
+//~^ ERROR the type of const parameters must not depend on other generic parameters
+//~| ERROR the type of const parameters must not depend on other generic parameters
+where
+ ConstAssert<{ MIN <= MAX }>: True;
+
+fn main() {}
--- /dev/null
+error[E0770]: the type of const parameters must not depend on other generic parameters
+ --> $DIR/issue-88997.rs:8:40
+ |
+LL | struct Range<T: PartialOrd, const MIN: T, const MAX: T>(T)
+ | ^ the type must not depend on the parameter `T`
+
+error[E0770]: the type of const parameters must not depend on other generic parameters
+ --> $DIR/issue-88997.rs:8:54
+ |
+LL | struct Range<T: PartialOrd, const MIN: T, const MAX: T>(T)
+ | ^ the type must not depend on the parameter `T`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0770`.
--- /dev/null
+// check-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+struct GenericStruct<const T: usize> { val: i64 }
+
+impl<const T: usize> From<GenericStruct<T>> for GenericStruct<{T + 1}> {
+ fn from(other: GenericStruct<T>) -> Self {
+ Self { val: other.val }
+ }
+}
+
+impl<const T: usize> From<GenericStruct<{T + 1}>> for GenericStruct<T> {
+ fn from(other: GenericStruct<{T + 1}>) -> Self {
+ Self { val: other.val }
+ }
+}
+
+fn main() {}
--- /dev/null
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(unused_braces, incomplete_features)]
+
+pub trait AnotherTrait{
+ const ARRAY_SIZE: usize;
+}
+pub trait Shard<T: AnotherTrait>:
+ AsMut<[[u8; T::ARRAY_SIZE]]>
+where
+ [(); T::ARRAY_SIZE]: Sized
+{
+}
+
+fn main() {}
--- /dev/null
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub struct Foo<T, const H: T>(T)
+//~^ ERROR the type of const parameters must not depend on other generic parameters
+where
+ [(); 1]:;
+
+fn main() {}
--- /dev/null
+error[E0770]: the type of const parameters must not depend on other generic parameters
+ --> $DIR/issue-90364.rs:4:28
+ |
+LL | pub struct Foo<T, const H: T>(T)
+ | ^ the type must not depend on the parameter `T`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0770`.
--- /dev/null
+// aux-build:legacy-const-generics.rs
+
+extern crate legacy_const_generics;
+
+fn foo<const N: usize>() {
+ let a = 1;
+ legacy_const_generics::foo(0, a, 2);
+ //~^ ERROR attempt to use a non-constant value in a constant
+
+ legacy_const_generics::foo(0, N, 2);
+
+ legacy_const_generics::foo(0, N + 1, 2);
+ //~^ ERROR generic parameters may not be used in const operations
+}
+
+fn main() {}
--- /dev/null
+error[E0435]: attempt to use a non-constant value in a constant
+ --> $DIR/legacy-const-generics-bad.rs:7:35
+ |
+LL | let a = 1;
+ | ----- help: consider using `const` instead of `let`: `const a`
+LL | legacy_const_generics::foo(0, a, 2);
+ | ^ non-constant value
+
+error: generic parameters may not be used in const operations
+ --> $DIR/legacy-const-generics-bad.rs:12:35
+ |
+LL | legacy_const_generics::foo(0, N + 1, 2);
+ | ^ cannot perform const operation using `N`
+ |
+ = help: const parameters may only be used as standalone arguments, i.e. `N`
+ = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0435`.
--- /dev/null
+// aux-build:legacy-const-generics.rs
+// run-pass
+
+#![feature(rustc_attrs)]
+
+extern crate legacy_const_generics;
+
+#[rustc_legacy_const_generics(1)]
+pub fn bar<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
+ [x, Y, z]
+}
+
+fn main() {
+ assert_eq!(legacy_const_generics::foo(0 + 0, 1 + 1, 2 + 2), [0, 2, 4]);
+ assert_eq!(legacy_const_generics::foo::<{1 + 1}>(0 + 0, 2 + 2), [0, 2, 4]);
+ // FIXME: Only works cross-crate
+ //assert_eq!(bar(0, 1, 2), [0, 1, 2]);
+}
+// needs-asm-support
+
#![feature(asm)]
const _: () = unsafe { asm!("nop") };
error[E0015]: inline assembly is not allowed in constants
- --> $DIR/inline_asm.rs:3:24
+ --> $DIR/inline_asm.rs:5:24
|
LL | const _: () = unsafe { asm!("nop") };
| ^^^^^^^^^^^
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+#![allow(non_camel_case_types)]
+
+const JSVAL_TAG_CLEAR: u32 = 0xFFFFFF80;
+const JSVAL_TYPE_INT32: u8 = 0x01;
+const JSVAL_TYPE_UNDEFINED: u8 = 0x02;
+#[repr(u32)]
+enum ValueTag {
+ JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | (JSVAL_TYPE_INT32 as u32),
+ JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | (JSVAL_TYPE_UNDEFINED as u32),
+}
+
+fn main() {
+ let _ = ValueTag::JSVAL_TAG_INT32;
+}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+
+static X2: u64 = !0 as u16 as u64;
+static Y2: u64 = !0 as u32 as u64;
+const X: u64 = !0 as u16 as u64;
+const Y: u64 = !0 as u32 as u64;
+
+fn main() {
+ assert_eq!(match 1 {
+ X => unreachable!(),
+ Y => unreachable!(),
+ _ => 1
+ }, 1);
+}
--- /dev/null
+fn main() {
+ const X: u32 = 1;
+ const Y: usize = unsafe { &X as *const u32 as usize }; //~ ERROR pointers cannot be cast to integers
+ println!("{}", Y);
+}
--- /dev/null
+error: pointers cannot be cast to integers during const eval
+ --> $DIR/issue-18294.rs:3:31
+ |
+LL | const Y: usize = unsafe { &X as *const u32 as usize };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: at compile-time, pointers do not have an integer value
+ = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+const U8_MAX_HALF: u8 = !0u8 / 2;
+const U16_MAX_HALF: u16 = !0u16 / 2;
+const U32_MAX_HALF: u32 = !0u32 / 2;
+const U64_MAX_HALF: u64 = !0u64 / 2;
+
+fn main() {
+ assert_eq!(U8_MAX_HALF, 0x7f);
+ assert_eq!(U16_MAX_HALF, 0x7fff);
+ assert_eq!(U32_MAX_HALF, 0x7fff_ffff);
+ assert_eq!(U64_MAX_HALF, 0x7fff_ffff_ffff_ffff);
+}
--- /dev/null
+const fn x() {
+ let t = true;
+ let x = || t; //~ ERROR function pointer
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: function pointers cannot appear in constant functions
+ --> $DIR/issue-37550-1.rs:3:9
+ |
+LL | let x = || t;
+ | ^
+ |
+ = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+ = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// run-pass
+
+const fn foo() -> i64 {
+ 3
+}
+
+const fn bar(x: i64) -> i64 {
+ x*2
+}
+
+fn main() {
+ let val = &(foo() % 2);
+ assert_eq!(*val, 1);
+
+ let val2 = &(bar(1+1) % 3);
+ assert_eq!(*val2, 1);
+}
let _val: &'static _ = &(Cell::new(1), 2).1; //~ ERROR temporary value dropped while borrowed
};
+const TEST_DROP: String = String::new();
+
fn main() {
// We must not promote things with interior mutability. Not even if we "project it away".
let _val: &'static _ = &(Cell::new(1), 2).0; //~ ERROR temporary value dropped while borrowed
let _val: &'static _ = &(1%0); //~ ERROR temporary value dropped while borrowed
let _val: &'static _ = &(1%(1-1)); //~ ERROR temporary value dropped while borrowed
let _val: &'static _ = &([1,2,3][4]+1); //~ ERROR temporary value dropped while borrowed
+
+ // No promotion of temporaries that need to be dropped.
+ let _val: &'static _ = &TEST_DROP;
+ //~^ ERROR temporary value dropped while borrowed
+ let _val: &'static _ = &&TEST_DROP;
+ //~^ ERROR temporary value dropped while borrowed
+ //~| ERROR temporary value dropped while borrowed
+ let _val: &'static _ = &(&TEST_DROP,);
+ //~^ ERROR temporary value dropped while borrowed
+ //~| ERROR temporary value dropped while borrowed
+ let _val: &'static _ = &[&TEST_DROP; 1];
+ //~^ ERROR temporary value dropped while borrowed
+ //~| ERROR temporary value dropped while borrowed
}
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:44:29
+ --> $DIR/promote-not.rs:46:29
|
LL | let _val: &'static _ = &(Cell::new(1), 2).0;
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:45:29
+ --> $DIR/promote-not.rs:47:29
|
LL | let _val: &'static _ = &(Cell::new(1), 2).1;
| ---------- ^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:48:29
+ --> $DIR/promote-not.rs:50:29
|
LL | let _val: &'static _ = &(1/0);
| ---------- ^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:49:29
+ --> $DIR/promote-not.rs:51:29
|
LL | let _val: &'static _ = &(1/(1-1));
| ---------- ^^^^^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:50:29
+ --> $DIR/promote-not.rs:52:29
|
LL | let _val: &'static _ = &(1%0);
| ---------- ^^^^^ creates a temporary which is freed while still in use
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:51:29
+ --> $DIR/promote-not.rs:53:29
|
LL | let _val: &'static _ = &(1%(1-1));
| ---------- ^^^^^^^^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'static`
-LL | let _val: &'static _ = &([1,2,3][4]+1);
+...
LL | }
| - temporary value is freed at the end of this statement
error[E0716]: temporary value dropped while borrowed
- --> $DIR/promote-not.rs:52:29
+ --> $DIR/promote-not.rs:54:29
|
LL | let _val: &'static _ = &([1,2,3][4]+1);
| ---------- ^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
| |
| type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:57:29
+ |
+LL | let _val: &'static _ = &TEST_DROP;
+ | ---------- ^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:59:29
+ |
+LL | let _val: &'static _ = &&TEST_DROP;
+ | ---------- ^^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:59:30
+ |
+LL | let _val: &'static _ = &&TEST_DROP;
+ | ---------- ^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:62:29
+ |
+LL | let _val: &'static _ = &(&TEST_DROP,);
+ | ---------- ^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
LL | }
| - temporary value is freed at the end of this statement
-error: aborting due to 13 previous errors
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:62:31
+ |
+LL | let _val: &'static _ = &(&TEST_DROP,);
+ | ---------- ^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:65:29
+ |
+LL | let _val: &'static _ = &[&TEST_DROP; 1];
+ | ---------- ^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/promote-not.rs:65:31
+ |
+LL | let _val: &'static _ = &[&TEST_DROP; 1];
+ | ---------- ^^^^^^^^^ - temporary value is freed at the end of this statement
+ | | |
+ | | creates a temporary which is freed while still in use
+ | type annotation requires that borrow lasts for `'static`
+
+error: aborting due to 20 previous errors
For more information about this error, try `rustc --explain E0716`.
--- /dev/null
+// compile-flags: --crate-type=lib
+#![feature(const_mut_refs)]
+#![feature(const_precise_live_drops)]
+#![feature(const_swap)]
+#![feature(raw_ref_op)]
+
+// Mutable borrow of a field with drop impl.
+pub const fn f() {
+ let mut a: (u32, Option<String>) = (0, None); //~ ERROR destructors cannot be evaluated
+ let _ = &mut a.1;
+}
+
+// Mutable borrow of a type with drop impl.
+pub const A1: () = {
+ let mut x = None; //~ ERROR destructors cannot be evaluated
+ let mut y = Some(String::new());
+ let a = &mut x;
+ let b = &mut y;
+ std::mem::swap(a, b);
+ std::mem::forget(y);
+};
+
+// Mutable borrow of a type with drop impl.
+pub const A2: () = {
+ let mut x = None;
+ let mut y = Some(String::new());
+ let a = &mut x;
+ let b = &mut y;
+ std::mem::swap(a, b);
+ std::mem::forget(y);
+ let _z = x; //~ ERROR destructors cannot be evaluated
+};
+
+// Shared borrow of a type that might be !Freeze and Drop.
+pub const fn g1<T>() {
+ let x: Option<T> = None; //~ ERROR destructors cannot be evaluated
+ let _ = x.is_some();
+}
+
+// Shared borrow of a type that might be !Freeze and Drop.
+pub const fn g2<T>() {
+ let x: Option<T> = None;
+ let _ = x.is_some();
+ let _y = x; //~ ERROR destructors cannot be evaluated
+}
+
+// Mutable raw reference to a Drop type.
+pub const fn address_of_mut() {
+ let mut x: Option<String> = None; //~ ERROR destructors cannot be evaluated
+ &raw mut x;
+
+ let mut y: Option<String> = None; //~ ERROR destructors cannot be evaluated
+ std::ptr::addr_of_mut!(y);
+}
+
+// Const raw reference to a Drop type. Conservatively assumed to allow mutation
+// until resolution of https://github.com/rust-lang/rust/issues/56604.
+pub const fn address_of_const() {
+ let x: Option<String> = None; //~ ERROR destructors cannot be evaluated
+ &raw const x;
+
+ let y: Option<String> = None; //~ ERROR destructors cannot be evaluated
+ std::ptr::addr_of!(y);
+}
--- /dev/null
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:9:9
+ |
+LL | let mut a: (u32, Option<String>) = (0, None);
+ | ^^^^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:15:9
+ |
+LL | let mut x = None;
+ | ^^^^^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:31:9
+ |
+LL | let _z = x;
+ | ^^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:36:9
+ |
+LL | let x: Option<T> = None;
+ | ^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:44:9
+ |
+LL | let _y = x;
+ | ^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:52:9
+ |
+LL | let mut y: Option<String> = None;
+ | ^^^^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:49:9
+ |
+LL | let mut x: Option<String> = None;
+ | ^^^^^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:62:9
+ |
+LL | let y: Option<String> = None;
+ | ^ constant functions cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:59:9
+ |
+LL | let x: Option<String> = None;
+ | ^ constant functions cannot evaluate destructors
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0493`.
--- /dev/null
+// compile-flags: --crate-type=lib
+// check-pass
+#![feature(const_mut_refs)]
+#![feature(const_precise_live_drops)]
+
+// Mutable reference allows only mutation of !Drop place.
+pub const fn f() {
+ let mut x: (Option<String>, u32) = (None, 0);
+ let mut a = 10;
+ *(&mut a) = 11;
+ x.1 = a;
+}
+
+// Mutable reference allows only mutation of !Drop place.
+pub const fn g() {
+ let mut a: (u32, Option<String>) = (0, None);
+ let _ = &mut a.0;
+}
+
+// Shared reference does not allow for mutation.
+pub const fn h() {
+ let x: Option<String> = None;
+ let _ = &x;
+}
--- /dev/null
+// Checks that unions use type based qualification. Regression test for issue #90268.
+#![feature(untagged_unions)]
+use std::cell::Cell;
+
+union U { i: u32, c: Cell<u32> }
+
+const C1: Cell<u32> = {
+ unsafe { U { c: Cell::new(0) }.c }
+};
+
+const C2: Cell<u32> = {
+ unsafe { U { i : 0 }.c }
+};
+
+const C3: Cell<u32> = {
+ let mut u = U { i: 0 };
+ u.i = 1;
+ unsafe { u.c }
+};
+
+const C4: U = U { i: 0 };
+
+const C5: [U; 1] = [U {i : 0}; 1];
+
+fn main() {
+ // Interior mutability should prevent promotion.
+ let _: &'static _ = &C1; //~ ERROR temporary value dropped while borrowed
+ let _: &'static _ = &C2; //~ ERROR temporary value dropped while borrowed
+ let _: &'static _ = &C3; //~ ERROR temporary value dropped while borrowed
+ let _: &'static _ = &C4; //~ ERROR temporary value dropped while borrowed
+ let _: &'static _ = &C5; //~ ERROR temporary value dropped while borrowed
+}
--- /dev/null
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/qualif-union.rs:27:26
+ |
+LL | let _: &'static _ = &C1;
+ | ---------- ^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/qualif-union.rs:28:26
+ |
+LL | let _: &'static _ = &C2;
+ | ---------- ^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/qualif-union.rs:29:26
+ |
+LL | let _: &'static _ = &C3;
+ | ---------- ^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+...
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/qualif-union.rs:30:26
+ |
+LL | let _: &'static _ = &C4;
+ | ---------- ^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+LL | let _: &'static _ = &C5;
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error[E0716]: temporary value dropped while borrowed
+ --> $DIR/qualif-union.rs:31:26
+ |
+LL | let _: &'static _ = &C5;
+ | ---------- ^^ creates a temporary which is freed while still in use
+ | |
+ | type annotation requires that borrow lasts for `'static`
+LL | }
+ | - temporary value is freed at the end of this statement
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
--- /dev/null
+// compile-flags: --crate-type lib --extern foo={{src-base}}/crate-loading/auxiliary/libfoo.rlib
+// normalize-stderr-test: "failed to mmap file '.*auxiliary/libfoo.rlib':.*" -> "failed to mmap file 'auxiliary/libfoo.rlib'"
+// don't emit warn logging, it's basically the same as the errors and it's annoying to normalize
+// rustc-env:RUSTC_LOG=error
+// edition:2018
+#![no_std]
+use ::foo; //~ ERROR invalid metadata files for crate `foo`
+//~| NOTE failed to mmap file
--- /dev/null
+error[E0786]: found invalid metadata files for crate `foo`
+ --> $DIR/invalid-rlib.rs:7:7
+ |
+LL | use ::foo;
+ | ^^^
+ |
+ = note: failed to mmap file 'auxiliary/libfoo.rlib'
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0786`.
let _ = nested::DeprecatedStruct {
//~^ ERROR use of deprecated struct `this_crate::nested::DeprecatedStruct`: text
i: 0 //~ ERROR use of deprecated field `this_crate::nested::DeprecatedStruct::i`: text
+ //~| ERROR field `i` of struct `this_crate::nested::DeprecatedStruct` is private
};
let _ = nested::DeprecatedUnitStruct; //~ ERROR use of deprecated unit struct `this_crate::nested::DeprecatedUnitStruct`: text
| ^^^^^^^^^^^^^^^^
error: use of deprecated unit struct `this_crate::nested::DeprecatedUnitStruct`: text
- --> $DIR/deprecation-lint.rs:283:25
+ --> $DIR/deprecation-lint.rs:284:25
|
LL | let _ = nested::DeprecatedUnitStruct;
| ^^^^^^^^^^^^^^^^^^^^
error: use of deprecated unit variant `this_crate::nested::Enum::DeprecatedVariant`: text
- --> $DIR/deprecation-lint.rs:285:31
+ --> $DIR/deprecation-lint.rs:286:31
|
LL | ... let _ = nested::Enum::DeprecatedVariant;
| ^^^^^^^^^^^^^^^^^
error: use of deprecated tuple struct `this_crate::nested::DeprecatedTupleStruct`: text
- --> $DIR/deprecation-lint.rs:287:25
+ --> $DIR/deprecation-lint.rs:288:25
|
LL | ... let _ = nested::DeprecatedTupleStruct (1);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:292:16
+ --> $DIR/deprecation-lint.rs:293:16
|
LL | Trait::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:294:25
+ --> $DIR/deprecation-lint.rs:295:25
|
LL | <Foo as Trait>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:296:16
+ --> $DIR/deprecation-lint.rs:297:16
|
LL | Trait::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:298:25
+ --> $DIR/deprecation-lint.rs:299:25
|
LL | ... <Foo as Trait>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar`
- --> $DIR/deprecation-lint.rs:316:13
+ --> $DIR/deprecation-lint.rs:317:13
|
LL | bar();
| ^^^
error: use of deprecated trait `this_crate::DeprecatedTrait`: text
- --> $DIR/deprecation-lint.rs:335:10
+ --> $DIR/deprecation-lint.rs:336:10
|
LL | impl DeprecatedTrait for S { }
| ^^^^^^^^^^^^^^^
error: use of deprecated trait `this_crate::DeprecatedTrait`: text
- --> $DIR/deprecation-lint.rs:337:24
+ --> $DIR/deprecation-lint.rs:338:24
|
LL | trait LocalTrait : DeprecatedTrait { }
| ^^^^^^^^^^^^^^^
error: use of deprecated struct `this_crate2::Deprecated`: text
- --> $DIR/deprecation-lint.rs:389:17
+ --> $DIR/deprecation-lint.rs:390:17
|
LL | let x = Deprecated {
| ^^^^^^^^^^
error: use of deprecated struct `this_crate2::Deprecated`: text
- --> $DIR/deprecation-lint.rs:398:13
+ --> $DIR/deprecation-lint.rs:399:13
|
LL | let Deprecated {
| ^^^^^^^^^^
error: use of deprecated struct `this_crate2::Deprecated`: text
- --> $DIR/deprecation-lint.rs:404:13
+ --> $DIR/deprecation-lint.rs:405:13
|
LL | let Deprecated
| ^^^^^^^^^^
error: use of deprecated tuple struct `this_crate2::Deprecated2`: text
- --> $DIR/deprecation-lint.rs:409:17
+ --> $DIR/deprecation-lint.rs:410:17
|
LL | let x = Deprecated2(1, 2, 3);
| ^^^^^^^^^^^
error: use of deprecated tuple struct `this_crate2::Deprecated2`: text
- --> $DIR/deprecation-lint.rs:419:13
+ --> $DIR/deprecation-lint.rs:420:13
|
LL | let Deprecated2
| ^^^^^^^^^^^
error: use of deprecated tuple struct `this_crate2::Deprecated2`: text
- --> $DIR/deprecation-lint.rs:428:13
+ --> $DIR/deprecation-lint.rs:429:13
|
LL | let Deprecated2
| ^^^^^^^^^^^
| ^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:291:13
+ --> $DIR/deprecation-lint.rs:292:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:293:16
+ --> $DIR/deprecation-lint.rs:294:16
|
LL | <Foo>::trait_deprecated(&foo);
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:295:13
+ --> $DIR/deprecation-lint.rs:296:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:297:16
+ --> $DIR/deprecation-lint.rs:298:16
|
LL | <Foo>::trait_deprecated_text(&foo);
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text
- --> $DIR/deprecation-lint.rs:302:13
+ --> $DIR/deprecation-lint.rs:303:13
|
LL | foo.trait_deprecated();
| ^^^^^^^^^^^^^^^^
error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text
- --> $DIR/deprecation-lint.rs:303:13
+ --> $DIR/deprecation-lint.rs:304:13
|
LL | foo.trait_deprecated_text();
| ^^^^^^^^^^^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable::override2`: text
- --> $DIR/deprecation-lint.rs:362:13
+ --> $DIR/deprecation-lint.rs:363:13
|
LL | override2: 3,
| ^^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable::override2`: text
- --> $DIR/deprecation-lint.rs:366:17
+ --> $DIR/deprecation-lint.rs:367:17
|
LL | let _ = x.override2;
| ^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable::override2`: text
- --> $DIR/deprecation-lint.rs:370:13
+ --> $DIR/deprecation-lint.rs:371:13
|
LL | override2: _
| ^^^^^^^^^^^^
error: use of deprecated field `this_crate2::Stable2::2`: text
- --> $DIR/deprecation-lint.rs:378:17
+ --> $DIR/deprecation-lint.rs:379:17
|
LL | let _ = x.2;
| ^^^
error: use of deprecated field `this_crate2::Stable2::2`: text
- --> $DIR/deprecation-lint.rs:383:20
+ --> $DIR/deprecation-lint.rs:384:20
|
LL | _)
| ^
error: use of deprecated field `this_crate2::Deprecated::inherit`: text
- --> $DIR/deprecation-lint.rs:391:13
+ --> $DIR/deprecation-lint.rs:392:13
|
LL | inherit: 1,
| ^^^^^^^^^^
error: use of deprecated field `this_crate2::Deprecated::inherit`: text
- --> $DIR/deprecation-lint.rs:395:17
+ --> $DIR/deprecation-lint.rs:396:17
|
LL | let _ = x.inherit;
| ^^^^^^^^^
error: use of deprecated field `this_crate2::Deprecated::inherit`: text
- --> $DIR/deprecation-lint.rs:400:13
+ --> $DIR/deprecation-lint.rs:401:13
|
LL | inherit: _,
| ^^^^^^^^^^
error: use of deprecated field `this_crate2::Deprecated2::0`: text
- --> $DIR/deprecation-lint.rs:412:17
+ --> $DIR/deprecation-lint.rs:413:17
|
LL | let _ = x.0;
| ^^^
error: use of deprecated field `this_crate2::Deprecated2::1`: text
- --> $DIR/deprecation-lint.rs:414:17
+ --> $DIR/deprecation-lint.rs:415:17
|
LL | let _ = x.1;
| ^^^
error: use of deprecated field `this_crate2::Deprecated2::2`: text
- --> $DIR/deprecation-lint.rs:416:17
+ --> $DIR/deprecation-lint.rs:417:17
|
LL | let _ = x.2;
| ^^^
error: use of deprecated field `this_crate2::Deprecated2::0`: text
- --> $DIR/deprecation-lint.rs:421:14
+ --> $DIR/deprecation-lint.rs:422:14
|
LL | (_,
| ^
error: use of deprecated field `this_crate2::Deprecated2::1`: text
- --> $DIR/deprecation-lint.rs:423:14
+ --> $DIR/deprecation-lint.rs:424:14
|
LL | _,
| ^
error: use of deprecated field `this_crate2::Deprecated2::2`: text
- --> $DIR/deprecation-lint.rs:425:14
+ --> $DIR/deprecation-lint.rs:426:14
|
LL | _)
| ^
-error: aborting due to 122 previous errors
+error[E0451]: field `i` of struct `this_crate::nested::DeprecatedStruct` is private
+ --> $DIR/deprecation-lint.rs:280:13
+ |
+LL | i: 0
+ | ^^^^ private field
+
+error: aborting due to 123 previous errors
+For more information about this error, try `rustc --explain E0451`.
--- /dev/null
+// compile-flags: --edition 2018
+fn foo() -> Result<(), ()> {
+ Ok(try!()); //~ ERROR use of deprecated `try` macro
+ Ok(try!(Ok(()))) //~ ERROR use of deprecated `try` macro
+}
+
+fn main() {
+ let _ = foo();
+}
--- /dev/null
+error: use of deprecated `try` macro
+ --> $DIR/try-macro-suggestion.rs:3:8
+ |
+LL | Ok(try!());
+ | ^^^^^^
+ |
+ = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated
+help: you can still access the deprecated `try!()` macro using the "raw identifier" syntax
+ |
+LL | Ok(r#try!());
+ | ++
+
+error: use of deprecated `try` macro
+ --> $DIR/try-macro-suggestion.rs:4:8
+ |
+LL | Ok(try!(Ok(())))
+ | ^^^^^^^^^^^^
+ |
+ = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated
+help: you can use the `?` operator instead
+ |
+LL - Ok(try!(Ok(())))
+LL + Ok(Ok(())?)
+ |
+help: alternatively, you can still access the deprecated `try!()` macro using the "raw identifier" syntax
+ |
+LL | Ok(r#try!(Ok(())))
+ | ++
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// run-pass
+
+#![allow(dead_code)]
+
+trait Trait { fn dummy(&self) { } }
+
+#[derive(Debug)]
+struct Foo<T: Trait> {
+ foo: T,
+}
+
+#[derive(Debug)]
+struct Bar<T> where T: Trait {
+ bar: T,
+}
+
+impl Trait for isize {}
+
+fn main() {
+ let a = Foo { foo: 12 };
+ let b = Bar { bar: 12 };
+ println!("{:?} {:?}", a, b);
+}
--- /dev/null
+// run-pass
+fn main() {}
+#[derive(Clone)]
+pub struct Little;
+#[derive(Clone)]
+pub struct Big(
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+ Little,
+);
+++ /dev/null
-// After #39485, this test used to pass, but that change was reverted
-// due to numerous inference failures like #39808, so it now fails
-// again. #39485 made it so that diverging types never propagate
-// upward; but we now do propagate such types upward in many more
-// cases.
-
-fn g() {
- &panic!() //~ ERROR mismatched types
-}
-
-fn f() -> isize {
- (return 1, return 2) //~ ERROR mismatched types
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/diverging-tuple-parts-39485.rs:8:5
- |
-LL | &panic!()
- | ^^^^^^^^^ expected `()`, found reference
- |
- = note: expected unit type `()`
- found reference `&_`
-help: try adding a return type
- |
-LL | fn g() -> &_ {
- | +++++
-help: consider removing the borrow
- |
-LL - &panic!()
-LL + panic!()
- |
-
-error[E0308]: mismatched types
- --> $DIR/diverging-tuple-parts-39485.rs:12:5
- |
-LL | fn f() -> isize {
- | ----- expected `isize` because of return type
-LL | (return 1, return 2)
- | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found tuple
- |
- = note: expected type `isize`
- found tuple `(!, !)`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// build-pass
+#![allow(dead_code)]
+// Regression test for #35546. Check that we are able to codegen
+// this. Before we had problems because of the drop glue signature
+// around dropping a trait object (specifically, when dropping the
+// `value` field of `Node<Send>`).
+
+struct Node<T: ?Sized + Send> {
+ next: Option<Box<Node<dyn Send>>>,
+ value: T,
+}
+
+fn clear(head: &mut Option<Box<Node<dyn Send>>>) {
+ match head.take() {
+ Some(node) => *head = node.next,
+ None => (),
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-pass
+// ignore-emscripten no threads support
+
+// Issue #787
+// Don't try to clean up uninitialized locals
+
+
+use std::thread;
+
+fn test_break() { loop { let _x: Box<isize> = break; } }
+
+fn test_cont() { let mut i = 0; while i < 1 { i += 1; let _x: Box<isize> = continue; } }
+
+fn test_ret() { let _x: Box<isize> = return; }
+
+fn test_panic() {
+ fn f() { let _x: Box<isize> = panic!(); }
+ thread::spawn(move|| f() ).join().unwrap_err();
+}
+
+fn test_panic_indirect() {
+ fn f() -> ! { panic!(); }
+ fn g() { let _x: Box<isize> = f(); }
+ thread::spawn(move|| g() ).join().unwrap_err();
+}
+
+pub fn main() {
+ test_break();
+ test_cont();
+ test_ret();
+ test_panic();
+ test_panic_indirect();
+}
--- /dev/null
+// run-pass
+
+// Demonstrate the use of the unguarded escape hatch with a type param in negative position
+// to assert that destructor will not access any dead data.
+//
+// Compare with ui/span/issue28498-reject-lifetime-param.rs
+
+// Demonstrate that a type param in negative position causes dropck to reject code
+// that might indirectly access previously dropped value.
+//
+// Compare with run-pass/issue28498-ugeh-with-passed-to-fn.rs
+
+#![feature(dropck_eyepatch)]
+
+#[derive(Debug)]
+struct ScribbleOnDrop(String);
+
+impl Drop for ScribbleOnDrop {
+ fn drop(&mut self) {
+ self.0 = format!("DROPPED");
+ }
+}
+
+struct Foo<T>(u32, T, Box<for <'r> fn(&'r T) -> String>);
+
+unsafe impl<#[may_dangle] T> Drop for Foo<T> {
+ fn drop(&mut self) {
+ // Use of `may_dangle` is sound, because destructor never passes a `self.1`
+ // to the callback (in `self.2`) despite having it available.
+ println!("Dropping Foo({}, _)", self.0);
+ }
+}
+
+fn callback(s: & &ScribbleOnDrop) -> String { format!("{:?}", s) }
+
+fn main() {
+ let (last_dropped, foo0);
+ let (foo1, first_dropped);
+
+ last_dropped = ScribbleOnDrop(format!("last"));
+ first_dropped = ScribbleOnDrop(format!("first"));
+ foo0 = Foo(0, &last_dropped, Box::new(callback));
+ foo1 = Foo(1, &first_dropped, Box::new(callback));
+
+ println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
+}
+++ /dev/null
-// edition:2015
-
-mod inner {
- fn global_inner(_: ::nonexistant::Foo) {
- //~^ ERROR failed to resolve: maybe a missing crate `nonexistant`?
- }
- fn crate_inner(_: crate::nonexistant::Foo) {
- //~^ ERROR failed to resolve: maybe a missing crate `nonexistant`?
- }
-
- fn bare_global(_: ::nonexistant) {
- //~^ ERROR cannot find type `nonexistant` in the crate root
- }
- fn bare_crate(_: crate::nonexistant) {
- //~^ ERROR cannot find type `nonexistant` in the crate root
- }
-}
-
-fn main() {
-
-}
+++ /dev/null
-error[E0433]: failed to resolve: maybe a missing crate `nonexistant`?
- --> $DIR/editions-crate-root-2015.rs:4:26
- |
-LL | fn global_inner(_: ::nonexistant::Foo) {
- | ^^^^^^^^^^^ maybe a missing crate `nonexistant`?
-
-error[E0433]: failed to resolve: maybe a missing crate `nonexistant`?
- --> $DIR/editions-crate-root-2015.rs:7:30
- |
-LL | fn crate_inner(_: crate::nonexistant::Foo) {
- | ^^^^^^^^^^^ maybe a missing crate `nonexistant`?
-
-error[E0412]: cannot find type `nonexistant` in the crate root
- --> $DIR/editions-crate-root-2015.rs:11:25
- |
-LL | fn bare_global(_: ::nonexistant) {
- | ^^^^^^^^^^^ not found in the crate root
-
-error[E0412]: cannot find type `nonexistant` in the crate root
- --> $DIR/editions-crate-root-2015.rs:14:29
- |
-LL | fn bare_crate(_: crate::nonexistant) {
- | ^^^^^^^^^^^ not found in the crate root
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0412, E0433.
-For more information about an error, try `rustc --explain E0412`.
--- /dev/null
+// run-pass
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+// Checks if the correct registers are being used to pass arguments
+// when the sysv64 ABI is specified.
+
+#![feature(rust_2018_preview)]
+
+pub trait Foo {}
+
+// should compile without the dyn trait feature flag
+fn foo(x: &dyn Foo) {}
+
+pub fn main() {}
#![feature(imported_main)]
-//~^ ERROR `main` is ambiguous (glob import vs glob import in the same module)
+//~^ ERROR `main` is ambiguous
mod m1 { pub(crate) fn main() {} }
mod m2 { pub(crate) fn main() {} }
-error[E0659]: `main` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `main` is ambiguous
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `main` could refer to the function imported here
--> $DIR/imported_main_conflict.rs:6:5
|
--- /dev/null
+// run-pass
+#![feature(core_intrinsics)]
+
+#[repr(i8)]
+pub enum Enum {
+ VariantA,
+ VariantB,
+}
+
+fn make_b() -> Enum { Enum::VariantB }
+
+fn main() {
+ assert_eq!(1, make_b() as i8);
+ assert_eq!(1, make_b() as u8);
+ assert_eq!(1, make_b() as i32);
+ assert_eq!(1, make_b() as u32);
+ assert_eq!(1, std::intrinsics::discriminant_value(&make_b()));
+}
--- /dev/null
+// run-pass
+macro_rules! fooN {
+ ($cur:ident $prev:ty) => {
+ #[allow(dead_code)]
+ enum $cur {
+ Empty,
+ First($prev),
+ Second($prev),
+ Third($prev),
+ Fourth($prev),
+ }
+ }
+}
+
+fooN!(Foo0 ());
+fooN!(Foo1 Foo0);
+fooN!(Foo2 Foo1);
+fooN!(Foo3 Foo2);
+fooN!(Foo4 Foo3);
+fooN!(Foo5 Foo4);
+fooN!(Foo6 Foo5);
+fooN!(Foo7 Foo6);
+fooN!(Foo8 Foo7);
+fooN!(Foo9 Foo8);
+fooN!(Foo10 Foo9);
+fooN!(Foo11 Foo10);
+fooN!(Foo12 Foo11);
+fooN!(Foo13 Foo12);
+fooN!(Foo14 Foo13);
+fooN!(Foo15 Foo14);
+fooN!(Foo16 Foo15);
+fooN!(Foo17 Foo16);
+fooN!(Foo18 Foo17);
+fooN!(Foo19 Foo18);
+fooN!(Foo20 Foo19);
+fooN!(Foo21 Foo20);
+fooN!(Foo22 Foo21);
+fooN!(Foo23 Foo22);
+fooN!(Foo24 Foo23);
+fooN!(Foo25 Foo24);
+fooN!(Foo26 Foo25);
+fooN!(Foo27 Foo26);
+
+fn main() {
+ let _foo = Foo27::Empty;
+}
+++ /dev/null
-// run-pass
-
-#![allow(dead_code)]
-#![allow(unused_variables)]
-// Checks if the correct registers are being used to pass arguments
-// when the sysv64 ABI is specified.
-
-#![feature(rust_2018_preview)]
-
-pub trait Foo {}
-
-// should compile without the dyn trait feature flag
-fn foo(x: &dyn Foo) {}
-
-pub fn main() {}
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
--> $DIR/E0659.rs:15:15
|
LL | collider::foo();
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `foo` could refer to the function imported here
--> $DIR/E0659.rs:10:13
|
// run-pass
-// only-i686
+// only-x86
trait A {
extern "fastcall" fn test1(i: i32);
// run-pass
-// only-i686
+// only-x86
#![feature(abi_thiscall)]
// run-pass
// revisions: x64 x32
// [x64]only-x86_64
-// [x32]only-i686
+// [x32]only-x86
#![feature(abi_vectorcall)]
--- /dev/null
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-28324.rs:8:24
+ |
+LL | pub static BAZ: u32 = *&error_message_count;
+ | ^^^^^^^^^^^^^^^^^^^^ use of extern static
+ |
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+extern "C" {
+ static error_message_count: u32;
+}
+
+pub static BAZ: u32 = *&error_message_count;
+//~^ ERROR use of extern static is unsafe and requires
+
+fn main() {}
--- /dev/null
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-28324.rs:8:25
+ |
+LL | pub static BAZ: u32 = *&error_message_count;
+ | ^^^^^^^^^^^^^^^^^^^ use of extern static
+ |
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+// only-x86_64
+
+#![feature(asm)]
+
+fn main() {
+ unsafe {
+ asm!("mov eax, {}", const 123);
+ //~^ ERROR const operands for inline assembly are unstable
+ }
+}
--- /dev/null
+error[E0658]: const operands for inline assembly are unstable
+ --> $DIR/feature-gate-asm_const.rs:7:29
+ |
+LL | asm!("mov eax, {}", const 123);
+ | ^^^^^^^^^
+ |
+ = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+ = help: add `#![feature(asm_const)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// compile-flags: --target mips-unknown-linux-gnu
+// needs-llvm-components: mips
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![crate_type = "rlib"]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+unsafe fn main() {
+ asm!("");
+ //~^ ERROR inline assembly is not stable yet on this architecture
+}
--- /dev/null
+error[E0658]: inline assembly is not stable yet on this architecture
+ --> $DIR/feature-gate-asm_experimental_arch.rs:19:5
+ |
+LL | asm!("");
+ | ^^^^^^^^
+ |
+ = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+ = help: add `#![feature(asm_experimental_arch)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// only-x86_64
+
+#![feature(asm)]
+
+fn main() {
+ unsafe {
+ asm!("mov eax, {}", sym main);
+ //~^ ERROR sym operands for inline assembly are unstable
+ }
+}
--- /dev/null
+error[E0658]: sym operands for inline assembly are unstable
+ --> $DIR/feature-gate-asm_sym.rs:7:29
+ |
+LL | asm!("mov eax, {}", sym main);
+ | ^^^^^^^^
+ |
+ = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+ = help: add `#![feature(asm_sym)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// Test that we allow unsizing even if there is an unchanged param in the
-// field getting unsized.
-struct A<T, U: ?Sized + 'static>(T, B<T, U>);
-struct B<T, U: ?Sized>(T, U);
-
-fn main() {
- let x: A<[u32; 1], [u32; 1]> = A([0; 1], B([0; 1], [0; 1]));
- let y: &A<[u32; 1], [u32]> = &x; //~ ERROR mismatched types
- assert_eq!(y.1.1.len(), 1);
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/feature-gate-relaxed_struct_unsize.rs:8:34
- |
-LL | let y: &A<[u32; 1], [u32]> = &x;
- | ------------------- ^^ expected slice `[u32]`, found array `[u32; 1]`
- | |
- | expected due to this
- |
- = note: expected reference `&A<[u32; 1], [u32]>`
- found reference `&A<[u32; 1], [u32; 1]>`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-pass
+#![allow(unreachable_code)]
+
+fn main() {
+ let mut v = Vec::new();
+
+ loop { v.push(break) }
+}
--- /dev/null
+// run-pass
+// pretty-expanded FIXME #23616
+
+#![allow(unused_variables)]
+
+pub fn main() {
+ let mut i: isize = 0;
+ while i < 1000000 {
+ i += 1;
+ let x = 3;
+ }
+}
--- /dev/null
+// run-pass
+
+#![allow(improper_ctypes)]
+#![allow(dead_code)]
+// Issue #901
+// pretty-expanded FIXME #23616
+
+mod libc {
+ extern "C" {
+ pub fn printf(x: ());
+ }
+}
+
+pub fn main() {}
// check that we don't normalize with trait defaults.
trait Collection<T> {
- type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter;
+ type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter, Self: 'iter;
type Family: CollectionFamily;
// Test associated type defaults with parameters
type Sibling<U>: Collection<U> =
// run-pass
trait Collection<T> {
- type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter;
+ type Iter<'iter>: Iterator<Item=&'iter T> where T: 'iter, Self: 'iter;
type Family: CollectionFamily;
// Test associated type defaults with parameters
type Sibling<U>: Collection<U> =
#![feature(generic_associated_types)]
pub trait X {
- type Y<'a>;
+ type Y<'a> where Self: 'a;
fn m(&self) -> Self::Y<'_>;
}
#![feature(generic_associated_types)]
trait Document {
- type Cursor<'a>: DocCursor<'a>;
+ type Cursor<'a>: DocCursor<'a> where Self: 'a;
fn cursor(&self) -> Self::Cursor<'_>;
}
pub trait SubTrait {}
pub trait SuperTrait {
- type SubType<'a>: SubTrait;
+ type SubType<'a>: SubTrait where Self: 'a;
fn get_sub<'a>(&'a mut self) -> Self::SubType<'a>;
}
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-76535.rs:6:10
|
-LL | type SubType<'a>: SubTrait;
+LL | type SubType<'a>: SubTrait where Self: 'a;
| ^^^^^^^ --
help: add missing lifetime argument
|
|
LL | pub trait SuperTrait {
| ---------- this trait cannot be made into an object...
-LL | type SubType<'a>: SubTrait;
+LL | type SubType<'a>: SubTrait where Self: 'a;
| ^^^^^^^ ...because it contains the generic associated type `SubType`
= help: consider moving `SubType` to another trait
|
LL | pub trait SuperTrait {
| ---------- this trait cannot be made into an object...
-LL | type SubType<'a>: SubTrait;
+LL | type SubType<'a>: SubTrait where Self: 'a;
| ^^^^^^^ ...because it contains the generic associated type `SubType`
= help: consider moving `SubType` to another trait
= note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` for `Box<SuperStruct>`
}
trait MapLike<K, V> {
- type VRefCont<'a>: RefCont<'a, V>;
+ type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
fn get<'a>(&'a self, key: &K) -> Option<Self::VRefCont<'a>>;
}
impl<K: Ord, V: 'static> MapLike<K, V> for std::collections::BTreeMap<K, V> {
- type VRefCont<'a> = &'a V;
+ type VRefCont<'a> where Self: 'a = &'a V;
fn get<'a>(&'a self, key: &K) -> Option<&'a V> {
std::collections::BTreeMap::get(self, key)
}
note: associated type defined here, with 1 lifetime parameter: `'a`
--> $DIR/issue-79422.rs:20:10
|
-LL | type VRefCont<'a>: RefCont<'a, V>;
+LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
| ^^^^^^^^ --
help: add missing lifetime argument
|
|
LL | trait MapLike<K, V> {
| ------- this trait cannot be made into an object...
-LL | type VRefCont<'a>: RefCont<'a, V>;
+LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
| ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
= help: consider moving `VRefCont` to another trait
|
LL | trait MapLike<K, V> {
| ------- this trait cannot be made into an object...
-LL | type VRefCont<'a>: RefCont<'a, V>;
+LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a;
| ^^^^^^^^ ...because it contains the generic associated type `VRefCont`
= help: consider moving `VRefCont` to another trait
= note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` for `Box<BTreeMap<u8, u8>>`
pub trait HasChildrenOf {
type T;
type TRef<'a>;
+ //~^ Missing required bounds
fn ref_children<'a>(&'a self) -> Vec<Self::TRef<'a>>;
fn take_children(self) -> Vec<Self::T>;
Right: HasChildrenOf,
{
type T = Either<Left::T, Right::T>;
+ // We used to error below because the where clause doesn't match the trait.
+ // Now, we error early on the trait itself.
type TRef<'a>
- //~^ `impl` associated type signature
- //~^^ `impl` associated type signature
where
<Left as HasChildrenOf>::T: 'a,
<Right as HasChildrenOf>::T: 'a
-error: `impl` associated type signature for `TRef` doesn't match `trait` associated type signature
- --> $DIR/issue-86787.rs:23:5
+error: Missing required bounds on TRef
+ --> $DIR/issue-86787.rs:11:5
|
-LL | type TRef<'a>;
- | -------------- expected
-...
-LL | / type TRef<'a>
-LL | |
-LL | |
-LL | | where
-LL | | <Left as HasChildrenOf>::T: 'a,
-LL | | <Right as HasChildrenOf>::T: 'a
-LL | | = Either<&'a Left::T, &'a Right::T>;
- | |________________________________________^ found
+LL | type TRef<'a>;
+ | ^^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where Self: 'a`
-error: `impl` associated type signature for `TRef` doesn't match `trait` associated type signature
- --> $DIR/issue-86787.rs:23:5
- |
-LL | type TRef<'a>;
- | -------------- expected
-...
-LL | / type TRef<'a>
-LL | |
-LL | |
-LL | | where
-LL | | <Left as HasChildrenOf>::T: 'a,
-LL | | <Right as HasChildrenOf>::T: 'a
-LL | | = Either<&'a Left::T, &'a Right::T>;
- | |________________________________________^ found
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
--- /dev/null
+#![feature(type_alias_impl_trait)]
+#![feature(generic_associated_types)]
+
+// See https://github.com/rust-lang/rust/issues/87258#issuecomment-883293367
+
+trait Trait1 {}
+
+struct Struct<'b>(&'b ());
+
+impl<'d> Trait1 for Struct<'d> {}
+
+pub trait Trait2 {
+ type FooFuture<'a>: Trait1;
+ fn foo<'a>() -> Self::FooFuture<'a>;
+}
+
+impl<'c, S: Trait2> Trait2 for &'c mut S {
+ type FooFuture<'a> = impl Trait1;
+ fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
+ Struct(unimplemented!())
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/issue-87258_a.rs:19:21
+ |
+LL | fn foo<'a>() -> Self::FooFuture<'a> {
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: hidden type `Struct<'_>` captures lifetime '_#7r
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
--- /dev/null
+#![feature(type_alias_impl_trait)]
+#![feature(generic_associated_types)]
+
+// See https://github.com/rust-lang/rust/issues/87258#issuecomment-883293367
+
+trait Trait1 {}
+
+struct Struct<'b>(&'b ());
+
+impl<'d> Trait1 for Struct<'d> {}
+
+pub trait Trait2 {
+ type FooFuture<'a>: Trait1;
+ fn foo<'a>() -> Self::FooFuture<'a>;
+}
+
+type Helper<'xenon, 'yttrium, KABOOM: Trait2> = impl Trait1;
+
+impl<'c, S: Trait2> Trait2 for &'c mut S {
+ type FooFuture<'a> = Helper<'c, 'a, S>;
+ fn foo<'a>() -> Self::FooFuture<'a> { //~ ERROR
+ Struct(unimplemented!())
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
+ --> $DIR/issue-87258_b.rs:21:21
+ |
+LL | fn foo<'a>() -> Self::FooFuture<'a> {
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+ = note: hidden type `Struct<'_>` captures lifetime '_#7r
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
trait SearchableResourceExt<Criteria>: SearchableResource<Criteria> {
type Future<'f, A: 'f + ?Sized, B: 'f>: Future<Output = Result<Vec<A::SearchResult>, ()>> + 'f
where
- A: SearchableResource<B>;
+ A: SearchableResource<B>,
+ Self: 'f;
fn search<'c>(&'c self, client: &'c ()) -> Self::Future<'c, Self, Criteria>;
}
type Future<'f, A, B: 'f>
where
A: SearchableResource<B> + ?Sized + 'f,
+ Self: 'f,
= SearchFutureTy<'f, A, B>;
fn search<'c>(&'c self, _client: &'c ()) -> Self::Future<'c, Self, Criteria> {
#![feature(generic_associated_types)]
trait GatTrait {
- type Gat<'a>;
+ type Gat<'a> where Self: 'a;
fn test(&self) -> Self::Gat<'_>;
}
trait SuperTrait<T>
where
+ Self: 'static,
for<'a> Self: GatTrait<Gat<'a> = &'a T>,
{
fn copy(&self) -> Self::Gat<'_> where T: Copy {
error[E0308]: mismatched types
- --> $DIR/issue-88360.rs:14:9
+ --> $DIR/issue-88360.rs:15:9
|
LL | trait SuperTrait<T>
| - this type parameter
--- /dev/null
+// check-pass
+
+#![feature(generic_associated_types)]
+
+trait Trait {
+ type Assoc<'a>;
+}
+
+fn f<T: Trait>(_: T, _: impl Fn(T::Assoc<'_>)) {}
+
+struct Type;
+
+impl Trait for Type {
+ type Assoc<'a> = ();
+}
+
+fn main() {
+ f(Type, |_|());
+}
--- /dev/null
+#![feature(generic_associated_types)]
+#![feature(type_alias_impl_trait)]
+
+fn main() {}
+
+trait A<'a> {
+ type B<'b>: Clone
+ // FIXME(generic_associated_types): Remove one of the below bounds
+ // https://github.com/rust-lang/rust/pull/90678#discussion_r744976085
+ where
+ 'a: 'b, Self: 'a, Self: 'b;
+
+ fn a(&'a self) -> Self::B<'a>;
+}
+
+struct C;
+
+impl<'a> A<'a> for C {
+ type B<'b> = impl Clone;
+ //~^ ERROR: lifetime bound not satisfied
+ //~| ERROR: could not find defining uses
+
+ fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope
+}
--- /dev/null
+error[E0478]: lifetime bound not satisfied
+ --> $DIR/issue-88595.rs:19:5
+ |
+LL | type B<'b> = impl Clone;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: lifetime parameter instantiated with the lifetime `'a` as defined here
+ --> $DIR/issue-88595.rs:18:6
+ |
+LL | impl<'a> A<'a> for C {
+ | ^^
+note: but lifetime parameter must outlive the lifetime `'b` as defined here
+ --> $DIR/issue-88595.rs:19:12
+ |
+LL | type B<'b> = impl Clone;
+ | ^^
+
+error: non-defining opaque type use in defining scope
+ --> $DIR/issue-88595.rs:23:23
+ |
+LL | fn a(&'a self) -> Self::B<'a> {}
+ | ^^^^^^^^^^^
+ |
+note: lifetime used multiple times
+ --> $DIR/issue-88595.rs:18:6
+ |
+LL | impl<'a> A<'a> for C {
+ | ^^
+LL | type B<'b> = impl Clone;
+ | ^^
+
+error: could not find defining uses
+ --> $DIR/issue-88595.rs:19:18
+ |
+LL | type B<'b> = impl Clone;
+ | ^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0478`.
--- /dev/null
+// edition:2018
+
+#![feature(generic_associated_types)]
+#![feature(type_alias_impl_trait)]
+
+use std::future::Future;
+
+trait MakeFut {
+ type Fut<'a> where Self: 'a;
+ fn make_fut<'a>(&'a self) -> Self::Fut<'a>;
+}
+
+impl MakeFut for &'_ mut () {
+ type Fut<'a> = impl Future<Output = ()>;
+ //~^ ERROR: the type `&mut ()` does not fulfill the required lifetime
+
+ fn make_fut<'a>(&'a self) -> Self::Fut<'a> {
+ async { () }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0477]: the type `&mut ()` does not fulfill the required lifetime
+ --> $DIR/issue-90014.rs:14:5
+ |
+LL | type Fut<'a> = impl Future<Output = ()>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: type must outlive the lifetime `'a` as defined here
+ --> $DIR/issue-90014.rs:14:14
+ |
+LL | type Fut<'a> = impl Future<Output = ()>;
+ | ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0477`.
#![feature(generic_associated_types)]
pub trait X {
- type Y<'a>;
+ type Y<'a> where Self: 'a;
fn m(&self) -> Self::Y<'_>;
}
--- /dev/null
+#![feature(generic_associated_types)]
+
+// check-fail
+
+use std::fmt::Debug;
+
+// We have a `&'a self`, so we need a `Self: 'a`
+trait Iterable {
+ type Item<'x>;
+ //~^ Missing required bounds
+ fn iter<'a>(&'a self) -> Self::Item<'a>;
+}
+
+/*
+impl<T> Iterable for T {
+ type Item<'a> = &'a T;
+ fn iter<'a>(&'a self) -> Self::Item<'a> {
+ self
+ }
+}
+*/
+
+// We have a `&'a T`, so we need a `T: 'x`
+trait Deserializer<T> {
+ type Out<'x>;
+ //~^ Missing required bounds
+ fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a>;
+}
+
+/*
+impl<T> Deserializer<T> for () {
+ type Out<'a> = &'a T;
+ fn deserialize<'a>(&self, input: &'a T) -> Self::Out<'a> { input }
+}
+*/
+
+// We have a `&'b T` and a `'b: 'a`, so it is implied that `T: 'a`. Therefore, we need a `T: 'x`
+trait Deserializer2<T> {
+ type Out<'x>;
+ //~^ Missing required bounds
+ fn deserialize2<'a, 'b: 'a>(&self, input1: &'b T) -> Self::Out<'a>;
+}
+
+// We have a `&'a T` and a `&'b U`, so we need a `T: 'x` and a `U: 'y`
+trait Deserializer3<T, U> {
+ type Out<'x, 'y>;
+ //~^ Missing required bounds
+ fn deserialize2<'a, 'b>(&self, input: &'a T, input2: &'b U) -> Self::Out<'a, 'b>;
+}
+
+// `T` is a param on the function, so it can't be named by the associated type
+trait Deserializer4 {
+ type Out<'x>;
+ fn deserialize<'a, T>(&self, input: &'a T) -> Self::Out<'a>;
+}
+
+struct Wrap<T>(T);
+
+// We pass `Wrap<T>` and we see `&'z Wrap<T>`, so we require `D: 'x`
+trait Des {
+ type Out<'x, D>;
+ //~^ Missing required bounds
+ fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, Wrap<T>>;
+}
+/*
+impl Des for () {
+ type Out<'x, D> = &'x D; // Not okay
+ fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, Wrap<T>> {
+ data
+ }
+}
+*/
+
+// We have `T` and `'z` as GAT substs. Because of `&'z Wrap<T>`, there is an
+// implied bound that `T: 'z`, so we require `D: 'x`
+trait Des2 {
+ type Out<'x, D>;
+ //~^ Missing required bounds
+ fn des<'z, T>(&self, data: &'z Wrap<T>) -> Self::Out<'z, T>;
+}
+/*
+impl Des2 for () {
+ type Out<'x, D> = &'x D;
+ fn des<'a, T>(&self, data: &'a Wrap<T>) -> Self::Out<'a, T> {
+ &data.0
+ }
+}
+*/
+
+// We see `&'z T`, so we require `D: 'x`
+trait Des3 {
+ type Out<'x, D>;
+ //~^ Missing required bounds
+ fn des<'z, T>(&self, data: &'z T) -> Self::Out<'z, T>;
+}
+/*
+impl Des3 for () {
+ type Out<'x, D> = &'x D;
+ fn des<'a, T>(&self, data: &'a T) -> Self::Out<'a, T> {
+ data
+ }
+}
+*/
+
+// Similar case to before, except with GAT.
+trait NoGat<'a> {
+ type Bar;
+ fn method(&'a self) -> Self::Bar;
+}
+
+// Lifetime is not on function; except `Self: 'a`
+// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one
+trait TraitLifetime<'a> {
+ type Bar<'b>;
+ //~^ Missing required bounds
+ fn method(&'a self) -> Self::Bar<'a>;
+}
+
+// Like above, but we have a where clause that can prove what we want
+// FIXME: we require two bounds (`where Self: 'a, Self: 'b`) when we should only require one
+trait TraitLifetimeWhere<'a> where Self: 'a {
+ type Bar<'b>;
+ //~^ Missing required bounds
+ fn method(&'a self) -> Self::Bar<'a>;
+}
+
+// Explicit bound instead of implicit; we want to still error
+trait ExplicitBound {
+ type Bar<'b>;
+ //~^ Missing required bounds
+ fn method<'b>(&self, token: &'b ()) -> Self::Bar<'b> where Self: 'b;
+}
+
+// The use of the GAT here is not in the return, we don't want to error
+trait NotInReturn {
+ type Bar<'b>;
+ fn method<'b>(&'b self) where Self::Bar<'b>: Debug;
+}
+
+// We obviously error for `Iterator`, but we should also error for `Item`
+trait IterableTwo {
+ type Item<'a>;
+ type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
+ //~^ Missing required bounds
+ fn iter<'a>(&'a self) -> Self::Iterator<'a>;
+}
+
+// We also should report region outlives clauses
+trait RegionOutlives {
+ type Bar<'a, 'b>;
+ //~^ Missing required bounds
+ fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y>;
+}
+
+/*
+impl Foo for () {
+ type Bar<'a, 'b> = &'a &'b ();
+ fn foo<'x, 'y>(&self, input: &'x &'y ()) -> Self::Bar<'x, 'y> {
+ input
+ }
+}
+*/
+
+// If there are multiple methods that return the GAT, require a set of clauses
+// that can be satisfied by *all* methods
+trait MultipleMethods {
+ type Bar<'me>;
+
+ fn gimme<'a>(&'a self) -> Self::Bar<'a>;
+ fn gimme_default(&self) -> Self::Bar<'static>;
+}
+
+fn main() {}
--- /dev/null
+error: Missing required bounds on Item
+ --> $DIR/self-outlives-lint.rs:9:5
+ |
+LL | type Item<'x>;
+ | ^^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where Self: 'x`
+
+error: Missing required bounds on Out
+ --> $DIR/self-outlives-lint.rs:25:5
+ |
+LL | type Out<'x>;
+ | ^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where T: 'x`
+
+error: Missing required bounds on Out
+ --> $DIR/self-outlives-lint.rs:39:5
+ |
+LL | type Out<'x>;
+ | ^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where T: 'x`
+
+error: Missing required bounds on Out
+ --> $DIR/self-outlives-lint.rs:46:5
+ |
+LL | type Out<'x, 'y>;
+ | ^^^^^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where T: 'x, U: 'y`
+
+error: Missing required bounds on Out
+ --> $DIR/self-outlives-lint.rs:61:5
+ |
+LL | type Out<'x, D>;
+ | ^^^^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where D: 'x`
+
+error: Missing required bounds on Out
+ --> $DIR/self-outlives-lint.rs:77:5
+ |
+LL | type Out<'x, D>;
+ | ^^^^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where D: 'x`
+
+error: Missing required bounds on Out
+ --> $DIR/self-outlives-lint.rs:92:5
+ |
+LL | type Out<'x, D>;
+ | ^^^^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where D: 'x`
+
+error: Missing required bounds on Bar
+ --> $DIR/self-outlives-lint.rs:114:5
+ |
+LL | type Bar<'b>;
+ | ^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where Self: 'a, Self: 'b`
+
+error: Missing required bounds on Bar
+ --> $DIR/self-outlives-lint.rs:122:5
+ |
+LL | type Bar<'b>;
+ | ^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where Self: 'a, Self: 'b`
+
+error: Missing required bounds on Bar
+ --> $DIR/self-outlives-lint.rs:129:5
+ |
+LL | type Bar<'b>;
+ | ^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where Self: 'b`
+
+error: Missing required bounds on Iterator
+ --> $DIR/self-outlives-lint.rs:143:5
+ |
+LL | type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where Self: 'a`
+
+error: Missing required bounds on Bar
+ --> $DIR/self-outlives-lint.rs:150:5
+ |
+LL | type Bar<'a, 'b>;
+ | ^^^^^^^^^^^^^^^^-
+ | |
+ | help: add the required where clauses: `where 'a: 'b`
+
+error: aborting due to 12 previous errors
+
use std::fmt::Display;
trait StreamingIterator {
- type Item<'a>;
+ type Item<'a> where Self: 'a;
// Applying the lifetime parameter `'a` to `Self::Item` inside the trait.
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}
-struct Foo<T: StreamingIterator> {
+struct Foo<T: StreamingIterator + 'static> {
// Applying a concrete lifetime to the constructor outside the trait.
bar: <T as StreamingIterator>::Item<'static>,
}
}
impl<I: StreamingIterator> StreamingIterator for StreamEnumerate<I> {
- type Item<'a> = (usize, I::Item<'a>);
+ type Item<'a> where Self: 'a = (usize, I::Item<'a>);
fn next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
match self.iter.next() {
None => None,
}
impl<I: Iterator> StreamingIterator for I {
- type Item<'a> = <I as Iterator>::Item;
+ type Item<'a> where Self: 'a = <I as Iterator>::Item;
fn next(&mut self) -> Option<<I as StreamingIterator>::Item<'_>> {
Iterator::next(self)
}
#![feature(generic_associated_types)]
trait A {
- type B<'a>;
+ type B<'a> where Self: 'a;
fn make_b<'a>(&'a self) -> Self::B<'a>;
}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+// Issue #1112
+// Alignment of interior pointers to dynamic-size types
+
+
+struct X<T> {
+ a: T,
+ b: u8,
+ c: bool,
+ d: u8,
+ e: u16,
+ f: u8,
+ g: u8
+}
+
+pub fn main() {
+ let x: X<isize> = X {
+ a: 12345678,
+ b: 9,
+ c: true,
+ d: 10,
+ e: 11,
+ f: 12,
+ g: 13
+ };
+ bar(x);
+}
+
+fn bar<T>(x: X<T>) {
+ assert_eq!(x.b, 9);
+ assert_eq!(x.c, true);
+ assert_eq!(x.d, 10);
+ assert_eq!(x.e, 11);
+ assert_eq!(x.f, 12);
+ assert_eq!(x.g, 13);
+}
--- /dev/null
+// run-pass
+
+fn quux<T>(x: T) -> T { let f = id::<T>; return f(x); }
+
+fn id<T>(x: T) -> T { return x; }
+
+pub fn main() { assert_eq!(quux(10), 10); }
--- /dev/null
+#![allow(dead_code)]
+#![feature(const_generics_defaults)]
+
+// This test checks that generic parameter re-ordering diagnostic suggestions mention that
+// consts come after types and lifetimes when the `const_generics_defaults` feature is enabled.
+// We cannot run rustfix on this test because of the above const generics warning.
+
+struct A;
+
+impl A {
+ pub fn do_things<T, 'a, 'b: 'a>() {
+ //~^ ERROR lifetime parameters must be declared prior to type parameters
+ println!("panic");
+ }
+}
+
+fn main() {}
--- /dev/null
+error: lifetime parameters must be declared prior to type parameters
+ --> $DIR/issue-59508-1.rs:11:25
+ |
+LL | pub fn do_things<T, 'a, 'b: 'a>() {
+ | ----^^--^^----- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b: 'a, T>`
+
+error: aborting due to previous error
+
--- /dev/null
+// run-rustfix
+
+#![allow(dead_code)]
+
+// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
+
+struct A;
+
+impl A {
+ pub fn do_things<'a, 'b: 'a, T>() {
+ //~^ ERROR lifetime parameters must be declared prior to type parameters
+ println!("panic");
+ }
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+#![allow(dead_code)]
+
+// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
+
+struct A;
+
+impl A {
+ pub fn do_things<T, 'a, 'b: 'a>() {
+ //~^ ERROR lifetime parameters must be declared prior to type parameters
+ println!("panic");
+ }
+}
+
+fn main() {}
--- /dev/null
+error: lifetime parameters must be declared prior to type parameters
+ --> $DIR/issue-59508.rs:10:25
+ |
+LL | pub fn do_things<T, 'a, 'b: 'a>() {
+ | ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
+
+error: aborting due to previous error
+
// run-pass
// edition:2021
-// compile-flags: -Zunstable-options
fn main() {
println!("hello, 2021");
--- /dev/null
+pub trait Trait<'a> {
+ type Item;
+}
+
+impl<'a> Trait<'a> for () {
+ type Item = ();
+}
+
+pub fn foo<T, F>(_: T, _: F)
+where
+ T: for<'a> Trait<'a>,
+ F: for<'a> FnMut(<T as Trait<'a>>::Item),
+{
+}
+
+fn main() {
+ foo((), drop)
+ //~^ ERROR type mismatch in function arguments
+ //~| ERROR size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
+}
--- /dev/null
+error[E0631]: type mismatch in function arguments
+ --> $DIR/issue-60283.rs:17:13
+ |
+LL | foo((), drop)
+ | --- ^^^^
+ | | |
+ | | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _`
+ | | found signature of `fn(()) -> _`
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `foo`
+ --> $DIR/issue-60283.rs:12:16
+ |
+LL | pub fn foo<T, F>(_: T, _: F)
+ | --- required by a bound in this
+...
+LL | F: for<'a> FnMut(<T as Trait<'a>>::Item),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
+
+error[E0277]: the size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
+ --> $DIR/issue-60283.rs:17:13
+ |
+LL | foo((), drop)
+ | --- ^^^^ doesn't have a size known at compile-time
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `Sized` is not implemented for `<() as Trait<'_>>::Item`
+note: required by a bound in `std::mem::drop`
+ --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+ |
+LL | pub fn drop<T>(_x: T) {}
+ | ^ required by this bound in `std::mem::drop`
+help: consider further restricting the associated type
+ |
+LL | fn main() where <() as Trait<'_>>::Item: Sized {
+ | ++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0277, E0631.
+For more information about an error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+
+pub trait Foo<'a> {
+ type Bar;
+ fn foo(&'a self) -> Self::Bar;
+}
+
+impl<'a, 'b, T: 'a> Foo<'a> for &'b T {
+ type Bar = &'a T;
+ fn foo(&'a self) -> &'a T {
+ self
+ }
+}
+
+pub fn uncallable<T, F>(x: T, f: F)
+where
+ T: for<'a> Foo<'a>,
+ F: for<'a> Fn(<T as Foo<'a>>::Bar),
+{
+ f(x.foo());
+}
+
+pub fn catalyst(x: &i32) {
+ broken(x, |_| {})
+}
+
+pub fn broken<F: Fn(&i32)>(x: &i32, f: F) {
+ uncallable(x, |y| f(y));
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+fn foo<T>(t: T) -> usize
+where
+ for<'a> &'a T: IntoIterator,
+ for<'a> <&'a T as IntoIterator>::IntoIter: ExactSizeIterator,
+{
+ t.into_iter().len()
+}
+
+fn main() {
+ foo::<Vec<u32>>(vec![]);
+}
}
fn main() {
- task(annotate( //~ type mismatch
+ task(annotate(
//~^ the size
//~^^ the trait bound
Annotate::<RefMutFamily<usize>>::new(),
-error[E0631]: type mismatch in closure arguments
- --> $DIR/issue-62529-1.rs:80:10
- |
-LL | task(annotate(
- | _____----_^
- | | |
- | | required by a bound introduced by this call
-LL | |
-LL | |
-LL | | Annotate::<RefMutFamily<usize>>::new(),
-LL | | |value: &mut usize| {
- | | ------------------- found signature of `for<'r> fn(&'r mut usize) -> _`
-LL | | *value = 2;
-LL | | }
-LL | | ));
- | |_____^ expected signature of `for<'r> fn(<RefMutFamily<usize> as FamilyLt<'r>>::Out) -> _`
- |
-note: required by a bound in `annotate`
- --> $DIR/issue-62529-1.rs:44:8
- |
-LL | fn annotate<F, Q>(_q: Annotate<Q>, func: F) -> impl Execute + 'static
- | -------- required by a bound in this
-LL | where
-LL | F: for<'r> FnOnce(<<Q as Inject>::I as FamilyLt<'r>>::Out) + 'static,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `annotate`
-
error[E0277]: the size for values of type `impl Execute` cannot be known at compilation time
--> $DIR/issue-62529-1.rs:80:10
|
LL | where P: Execute + 'static {
| ^^^^^^^ required by this bound in `task`
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
-Some errors have detailed explanations: E0277, E0631.
-For more information about an error, try `rustc --explain E0277`.
+For more information about this error, try `rustc --explain E0277`.
+// check-pass
+
pub trait MyTrait<'a> {
type Output: 'a;
fn gimme_value(&self) -> Self::Output;
fn main() {
let struc = MyStruct;
- meow(struc, |foo| { //~ type mismatch
+ meow(struc, |foo| {
println!("{:?}", foo);
})
}
+++ /dev/null
-error[E0631]: type mismatch in closure arguments
- --> $DIR/issue-70120.rs:26:5
- |
-LL | meow(struc, |foo| {
- | ^^^^ ----- found signature of `for<'r> fn(&'r usize) -> _`
- | |
- | expected signature of `for<'any2> fn(<MyStruct as MyTrait<'any2>>::Output) -> _`
- |
-note: required by a bound in `meow`
- --> $DIR/issue-70120.rs:18:8
- |
-LL | fn meow<T, F>(t: T, f: F)
- | ---- required by a bound in this
-...
-LL | F: for<'any2> Fn(<T as MyTrait<'any2>>::Output),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `meow`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0631`.
--- /dev/null
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:52:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:52:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:52:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:52:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:52:5
+ |
+LL | foo(bar, "string", |s| s.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, &'a str) {bar}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: implementation of `Parser` is not general enough
+ --> $DIR/issue-71955.rs:58:5
+ |
+LL | foo(baz, "string", |s| s.0.len() == 5);
+ | ^^^ implementation of `Parser` is not general enough
+ |
+ = note: `for<'a> fn(&'a str) -> (&'a str, Wrapper<'a>) {baz}` must implement `Parser<'0>`, for any lifetime `'0`...
+ = note: ...but it actually implements `Parser<'1>`, for some specific lifetime `'1`
+
+error: aborting due to 10 previous errors
+
--- /dev/null
+error: fatal error triggered by #[rustc_error]
+ --> $DIR/issue-71955.rs:42:1
+ |
+LL | fn main() {
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// ignore-compare-mode-nll
+// revisions: migrate nll
+// [nll]compile-flags: -Zborrowck=mir
+// check-fail
+
+#![feature(rustc_attrs)]
+
+trait Parser<'s> {
+ type Output;
+
+ fn call(&self, input: &'s str) -> (&'s str, Self::Output);
+}
+
+impl<'s, F, T> Parser<'s> for F
+where F: Fn(&'s str) -> (&'s str, T) {
+ type Output = T;
+ fn call(&self, input: &'s str) -> (&'s str, T) {
+ self(input)
+ }
+}
+
+fn foo<F1, F2>(
+ f1: F1,
+ base: &'static str,
+ f2: F2
+)
+where
+ F1: for<'a> Parser<'a>,
+ F2: FnOnce(&<F1 as Parser>::Output) -> bool
+{
+ let s: String = base.to_owned();
+ let str_ref = s.as_ref();
+ let (remaining, produced) = f1.call(str_ref);
+ assert!(f2(&produced));
+ assert_eq!(remaining.len(), 0);
+}
+
+struct Wrapper<'a>(&'a str);
+
+// Because nll currently succeeds and migrate doesn't
+#[rustc_error]
+fn main() {
+ //[nll]~^ fatal
+ fn bar<'a>(s: &'a str) -> (&'a str, &'a str) {
+ (&s[..1], &s[..])
+ }
+
+ fn baz<'a>(s: &'a str) -> (&'a str, Wrapper<'a>) {
+ (&s[..1], Wrapper(&s[..]))
+ }
+
+ foo(bar, "string", |s| s.len() == 5);
+ //[migrate]~^ ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ foo(baz, "string", |s| s.0.len() == 5);
+ //[migrate]~^ ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+ //[migrate]~| ERROR implementation of `Parser` is not general enough
+}
--- /dev/null
+// check-pass
+
+use std::marker::PhantomData;
+
+trait A<'a> {
+ type B;
+ fn b(self) -> Self::B;
+}
+
+struct T;
+struct S<'a>(PhantomData<&'a ()>);
+
+impl<'a> A<'a> for T {
+ type B = S<'a>;
+ fn b(self) -> Self::B {
+ S(PhantomData)
+ }
+}
+
+fn s<TT, F>(t: TT, f: F)
+where
+ TT: for<'a> A<'a>,
+ F: for<'a> FnOnce(<TT as A<'a>>::B)
+{
+ f(t.b());
+}
+
+fn main() {
+ s(T, |_| {});
+}
--- /dev/null
+// check-pass
+
+use std::ops::Deref;
+
+struct Data {
+ boxed: Box<&'static i32>
+}
+
+impl Data {
+ fn use_data(&self, user: impl for <'a> FnOnce(<Box<&'a i32> as Deref>::Target)) {
+ user(*self.boxed)
+ }
+}
+
+fn main() {}
fn main() {
let v = Unit2.m(
//~^ ERROR type mismatch
- //~| ERROR type mismatch
L {
+ //~^ ERROR type mismatch
f : |x| { drop(x); Unit4 }
});
}
= note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
error[E0271]: type mismatch resolving `for<'r> <[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as FnOnce<((&'r u8,),)>>::Output == Unit3`
- --> $DIR/issue-62203-hrtb-ice.rs:38:19
+ --> $DIR/issue-62203-hrtb-ice.rs:40:9
|
-LL | let v = Unit2.m(
- | ^ expected struct `Unit4`, found struct `Unit3`
+LL | let v = Unit2.m(
+ | - required by a bound introduced by this call
+LL |
+LL | / L {
+LL | |
+LL | | f : |x| { drop(x); Unit4 }
+LL | | });
+ | |_________^ expected struct `Unit4`, found struct `Unit3`
|
note: required because of the requirements on the impl of `for<'r> T0<'r, (&'r u8,)>` for `L<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39]>`
--> $DIR/issue-62203-hrtb-ice.rs:17:16
--- /dev/null
+// check-pass
+
+trait Base<'f> {
+ type Assoc;
+
+ fn do_something(&self);
+}
+
+trait ForAnyLifetime: for<'f> Base<'f> {}
+
+impl<T> ForAnyLifetime for T where T: for<'f> Base<'f> {}
+
+trait CanBeDynamic: ForAnyLifetime + for<'f> Base<'f, Assoc = ()> {}
+
+fn foo(a: &dyn CanBeDynamic) {
+ a.do_something();
+}
+
+struct S;
+
+impl<'a> Base<'a> for S {
+ type Assoc = ();
+
+ fn do_something(&self) {}
+}
+
+impl CanBeDynamic for S {}
+
+fn main() {
+ let s = S;
+ foo(&s);
+}
--- /dev/null
+#![feature(decl_macro)]
+
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum Field {
+ RootCtxt,
+ MacroCtxt,
+}
+
+#[rustfmt::skip]
+macro x(
+ $macro_name:ident,
+ $macro2_name:ident,
+ $type_name:ident,
+ $field_name:ident,
+ $const_name:ident
+) {
+ #[derive(Copy, Clone)]
+ pub struct $type_name {
+ pub field: Field,
+ pub $field_name: Field,
+ }
+
+ pub const $const_name: $type_name =
+ $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt };
+
+ #[macro_export]
+ macro_rules! $macro_name {
+ (check_fields_of $e:expr) => {{
+ let e = $e;
+ assert_eq!(e.field, Field::MacroCtxt);
+ assert_eq!(e.$field_name, Field::RootCtxt);
+ }};
+ (check_fields) => {{
+ assert_eq!($const_name.field, Field::MacroCtxt);
+ assert_eq!($const_name.$field_name, Field::RootCtxt);
+ }};
+ (construct) => {
+ $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt }
+ };
+ }
+
+ pub macro $macro2_name {
+ (check_fields_of $e:expr) => {{
+ let e = $e;
+ assert_eq!(e.field, Field::MacroCtxt);
+ assert_eq!(e.$field_name, Field::RootCtxt);
+ }},
+ (check_fields) => {{
+ assert_eq!($const_name.field, Field::MacroCtxt);
+ assert_eq!($const_name.$field_name, Field::RootCtxt);
+ }},
+ (construct) => {
+ $type_name { field: Field::MacroCtxt, $field_name: Field::RootCtxt }
+ }
+ }
+}
+
+x!(test_fields, test_fields2, MyStruct, field, MY_CONST);
+
+pub fn check_fields(s: MyStruct) {
+ test_fields!(check_fields_of s);
+}
+
+pub fn check_fields_local() {
+ test_fields!(check_fields);
+ test_fields2!(check_fields);
+
+ let s1 = test_fields!(construct);
+ test_fields!(check_fields_of s1);
+
+ let s2 = test_fields2!(construct);
+ test_fields2!(check_fields_of s2);
+}
--- /dev/null
+#![feature(decl_macro)]
+
+#[derive(PartialEq, Eq, Debug)]
+pub enum Method {
+ DefaultMacroCtxt,
+ DefaultRootCtxt,
+ OverrideMacroCtxt,
+ OverrideRootCtxt,
+}
+
+#[rustfmt::skip]
+macro x($macro_name:ident, $macro2_name:ident, $trait_name:ident, $method_name:ident) {
+ pub trait $trait_name {
+ fn method(&self) -> Method {
+ Method::DefaultMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::DefaultRootCtxt
+ }
+ }
+
+ impl $trait_name for () {}
+ impl $trait_name for bool {
+ fn method(&self) -> Method {
+ Method::OverrideMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::OverrideRootCtxt
+ }
+ }
+
+ #[macro_export]
+ macro_rules! $macro_name {
+ (check_resolutions) => {
+ assert_eq!(().method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt);
+ assert_eq!(().$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt);
+
+ assert_eq!(false.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt);
+ assert_eq!(false.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt);
+
+ assert_eq!('a'.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt);
+ assert_eq!('a'.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt);
+
+ assert_eq!(1i32.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt);
+ assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt);
+
+ assert_eq!(1i64.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt);
+ assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt);
+ };
+ (assert_no_override $v:expr) => {
+ assert_eq!($v.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt);
+ assert_eq!($v.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt);
+ };
+ (assert_override $v:expr) => {
+ assert_eq!($v.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt);
+ assert_eq!($v.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt);
+ };
+ (impl for $t:ty) => {
+ impl $trait_name for $t {
+ fn method(&self) -> Method {
+ Method::OverrideMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::OverrideRootCtxt
+ }
+ }
+ };
+ }
+
+ pub macro $macro2_name {
+ (check_resolutions) => {
+ assert_eq!(().method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&()), Method::DefaultMacroCtxt);
+ assert_eq!(().$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&()), Method::DefaultRootCtxt);
+
+ assert_eq!(false.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&false), Method::OverrideMacroCtxt);
+ assert_eq!(false.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&false), Method::OverrideRootCtxt);
+
+ assert_eq!('a'.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&'a'), Method::DefaultMacroCtxt);
+ assert_eq!('a'.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&'a'), Method::DefaultRootCtxt);
+
+ assert_eq!(1i32.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i32), Method::OverrideMacroCtxt);
+ assert_eq!(1i32.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i32), Method::OverrideRootCtxt);
+
+ assert_eq!(1i64.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&1i64), Method::OverrideMacroCtxt);
+ assert_eq!(1i64.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&1i64), Method::OverrideRootCtxt);
+ },
+ (assert_no_override $v:expr) => {
+ assert_eq!($v.method(), Method::DefaultMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::DefaultMacroCtxt);
+ assert_eq!($v.$method_name(), Method::DefaultRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::DefaultRootCtxt);
+ },
+ (assert_override $v:expr) => {
+ assert_eq!($v.method(), Method::OverrideMacroCtxt);
+ assert_eq!($trait_name::method(&$v), Method::OverrideMacroCtxt);
+ assert_eq!($v.$method_name(), Method::OverrideRootCtxt);
+ assert_eq!($trait_name::$method_name(&$v), Method::OverrideRootCtxt);
+ },
+ (impl for $t:ty) => {
+ impl $trait_name for $t {
+ fn method(&self) -> Method {
+ Method::OverrideMacroCtxt
+ }
+
+ fn $method_name(&self) -> Method {
+ Method::OverrideRootCtxt
+ }
+ }
+ }
+ }
+}
+
+x!(test_trait, test_trait2, MyTrait, method);
+
+impl MyTrait for char {}
+test_trait!(impl for i32);
+test_trait2!(impl for i64);
+
+pub fn check_crate_local() {
+ test_trait!(check_resolutions);
+ test_trait2!(check_resolutions);
+}
+
+// Check that any comparison of idents at monomorphization time is correct
+pub fn check_crate_local_generic<T: MyTrait, U: MyTrait>(t: T, u: U) {
+ test_trait!(check_resolutions);
+ test_trait2!(check_resolutions);
+
+ test_trait!(assert_no_override t);
+ test_trait2!(assert_no_override t);
+ test_trait!(assert_override u);
+ test_trait2!(assert_override u);
+}
--- /dev/null
+#![feature(decl_macro)]
+
+macro x() {
+ pub struct MyStruct;
+}
+
+x!();
--- /dev/null
+#![feature(decl_macro)]
+
+macro x($macro_name:ident) {
+ #[macro_export]
+ macro_rules! $macro_name {
+ (define) => {
+ pub struct MyStruct;
+ };
+ (create) => {
+ MyStruct {}
+ };
+ }
+}
+
+x!(my_struct);
--- /dev/null
+#![feature(decl_macro)]
+
+#[rustfmt::skip]
+macro x($macro_name:ident, $macro2_name:ident, $type_name:ident, $variant_name:ident) {
+ #[repr(u8)]
+ pub enum $type_name {
+ Variant = 0,
+ $variant_name = 1,
+ }
+
+ #[macro_export]
+ macro_rules! $macro_name {
+ () => {{
+ assert_eq!($type_name::Variant as u8, 0);
+ assert_eq!($type_name::$variant_name as u8, 1);
+ assert_eq!(<$type_name>::Variant as u8, 0);
+ assert_eq!(<$type_name>::$variant_name as u8, 1);
+ }};
+ }
+
+ pub macro $macro2_name {
+ () => {{
+ assert_eq!($type_name::Variant as u8, 0);
+ assert_eq!($type_name::$variant_name as u8, 1);
+ assert_eq!(<$type_name>::Variant as u8, 0);
+ assert_eq!(<$type_name>::$variant_name as u8, 1);
+ }},
+ }
+}
+
+x!(test_variants, test_variants2, MyEnum, Variant);
+
+pub fn check_variants() {
+ test_variants!();
+ test_variants2!();
+}
--- /dev/null
+// Check that a marco from another crate can define an item in one expansion
+// and use it from another, without it being visible to everyone.
+// This requires that the definition of `my_struct` preserves the hygiene
+// information for the tokens in its definition.
+
+// check-pass
+// aux-build:use_by_macro.rs
+
+#![feature(type_name_of_val)]
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+enum MyStruct {}
+my_struct!(define);
+
+fn main() {
+ let x = my_struct!(create);
+}
--- /dev/null
+// Test that fields on a struct defined in another crate are resolved correctly
+// their names differ only in `SyntaxContext`.
+
+// run-pass
+// aux-build:fields.rs
+
+extern crate fields;
+
+use fields::*;
+
+fn main() {
+ check_fields_local();
+
+ test_fields!(check_fields);
+ test_fields2!(check_fields);
+
+ let s1 = test_fields!(construct);
+ check_fields(s1);
+ test_fields!(check_fields_of s1);
+
+ let s2 = test_fields2!(construct);
+ check_fields(s2);
+ test_fields2!(check_fields_of s2);
+}
--- /dev/null
+// Check that globs cannot import hygienic identifiers from a macro expansion
+// in another crate. `my_struct` is a `macro_rules` macro, so the struct it
+// defines is only not imported because `my_struct` is defined by a macros 2.0
+// macro.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+mod m {
+ use use_by_macro::*;
+
+ my_struct!(define);
+}
+
+use m::*;
+
+fn main() {
+ let x = my_struct!(create);
+ //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
--- /dev/null
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+ --> $DIR/cross-crate-glob-hygiene.rs:21:13
+ |
+LL | let x = my_struct!(create);
+ | ^^^^^^^^^^^^^^^^^^ not found in this scope
+ |
+ = note: this error originates in the macro `my_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
--- /dev/null
+// Test that methods defined in another crate are resolved correctly their
+// names differ only in `SyntaxContext`. This also checks that any name
+// resolution done when monomorphizing is correct.
+
+// run-pass
+// aux-build:methods.rs
+
+extern crate methods;
+
+use methods::*;
+
+struct A;
+struct B;
+struct C;
+
+impl MyTrait for A {}
+test_trait!(impl for B);
+test_trait2!(impl for C);
+
+fn main() {
+ check_crate_local();
+ check_crate_local_generic(A, B);
+ check_crate_local_generic(A, C);
+
+ test_trait!(check_resolutions);
+ test_trait2!(check_resolutions);
+ test_trait!(assert_no_override A);
+ test_trait2!(assert_no_override A);
+ test_trait!(assert_override B);
+ test_trait2!(assert_override B);
+ test_trait!(assert_override C);
+ test_trait2!(assert_override C);
+}
--- /dev/null
+// Check that two items defined in another crate that have identifiers that
+// only differ by `SyntaxContext` do not cause name collisions when imported
+// in another crate.
+
+// check-pass
+// aux-build:needs_hygiene.rs
+
+extern crate needs_hygiene;
+
+use needs_hygiene::*;
+
+fn main() {}
--- /dev/null
+// Check that an identifier from a 2.0 macro in another crate cannot be
+// resolved with an identifier that's not from a macro expansion.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+my_struct!(define);
+
+fn main() {
+ let x = MyStruct {};
+ //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
--- /dev/null
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+ --> $DIR/cross-crate-name-hiding-2.rs:13:13
+ |
+LL | let x = MyStruct {};
+ | ^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
--- /dev/null
+// Check that an item defined by a 2.0 macro in another crate cannot be used in
+// another crate.
+
+// aux-build:pub_hygiene.rs
+
+extern crate pub_hygiene;
+
+use pub_hygiene::*;
+
+fn main() {
+ let x = MyStruct {};
+ //~^ ERROR cannot find struct, variant or union type `MyStruct` in this scope
+}
--- /dev/null
+error[E0422]: cannot find struct, variant or union type `MyStruct` in this scope
+ --> $DIR/cross-crate-name-hiding.rs:11:13
+ |
+LL | let x = MyStruct {};
+ | ^^^^^^^^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0422`.
--- /dev/null
+// Check that items with identical `SyntaxContext` conflict even when that
+// context involves a mark from another crate.
+
+// aux-build:use_by_macro.rs
+
+extern crate use_by_macro;
+
+use use_by_macro::*;
+
+my_struct!(define);
+//~^ ERROR the name `MyStruct` is defined multiple times
+my_struct!(define);
+
+fn main() {}
--- /dev/null
+error[E0428]: the name `MyStruct` is defined multiple times
+ --> $DIR/cross-crate-redefine.rs:10:1
+ |
+LL | my_struct!(define);
+ | ^^^^^^^^^^^^^^^^^^ `MyStruct` redefined here
+LL |
+LL | my_struct!(define);
+ | ------------------ previous definition of the type `MyStruct` here
+ |
+ = note: `MyStruct` must be defined only once in the type namespace of this module
+ = note: this error originates in the macro `my_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0428`.
--- /dev/null
+// Test that variants of an enum defined in another crate are resolved
+// correctly when their names differ only in `SyntaxContext`.
+
+// run-pass
+// aux-build:variants.rs
+
+extern crate variants;
+
+use variants::*;
+
+fn main() {
+ check_variants();
+
+ test_variants!();
+ test_variants2!();
+
+ assert_eq!(MyEnum::Variant as u8, 1);
+}
+++ /dev/null
-// check-pass
-// aux-build:needs_hygiene.rs
-
-extern crate needs_hygiene;
-
-use needs_hygiene::*;
-
-fn main() {}
--- /dev/null
+// run-pass
+// shouldn't affect evaluation of $ex:
+macro_rules! bad_macro {
+ ($ex:expr) => ({(|_x| { $ex }) (9) })
+}
+
+fn takes_x(_x : isize) {
+ assert_eq!(bad_macro!(_x),8);
+}
+fn main() {
+ takes_x(8);
+}
error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
- --> $DIR/auto-trait-leak2.rs:13:5
+ --> $DIR/auto-trait-leak2.rs:13:10
|
LL | fn before() -> impl Fn(i32) {
| ------------ within this `impl Fn<(i32,)>`
...
LL | send(before());
- | ^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+ | ---- ^^^^^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc<Cell<i32>>`
= note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22]`
| ^^^^ required by this bound in `send`
error[E0277]: `Rc<Cell<i32>>` cannot be sent between threads safely
- --> $DIR/auto-trait-leak2.rs:16:5
+ --> $DIR/auto-trait-leak2.rs:16:10
|
LL | send(after());
- | ^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+ | ---- ^^^^^^^ `Rc<Cell<i32>>` cannot be sent between threads safely
+ | |
+ | required by a bound introduced by this call
...
LL | fn after() -> impl Fn(i32) {
| ------------ within this `impl Fn<(i32,)>`
|
LL | foo::<str>("".to_string());
| ^^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
--- /dev/null
+// check-pass
+
+fn fibs(n: u32) -> impl Iterator<Item=u128> {
+ (0 .. n)
+ .scan((0, 1), |st, _| {
+ *st = (st.1, st.0 + st.1);
+ Some(*st)
+ })
+ .map(&|(f, _)| f)
+}
+
+fn main() {
+ println!("{:?}", fibs(10).collect::<Vec<_>>());
+}
--- /dev/null
+// run-pass
+// Regression test for #49685: drop elaboration was not revealing the
+// value of `impl Trait` returns, leading to an ICE.
+
+fn main() {
+ let _ = Some(())
+ .into_iter()
+ .flat_map(|_| Some(()).into_iter().flat_map(func));
+}
+
+fn func(_: ()) -> impl Iterator<Item = ()> {
+ Some(()).into_iter().flat_map(|_| vec![])
+}
--- /dev/null
+// run-pass
+fn foo() -> impl Into<for<'a> fn(&'a ())> {
+ (|_| {}) as for<'a> fn(&'a ())
+}
+
+fn main() {
+ foo().into()(&());
+}
|
LL | foo::<String>('a');
| ^^^^^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
| ^^^^^^^^^ ^^^^^^^^^^^^^ explicit generic argument not allowed
| |
| explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to previous error
//~^ ERROR defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
//~| WARNING this was previously accepted by the compiler but is being phased out
//~| ERROR `impl Trait` not allowed outside of function and method return types
+//~| ERROR no nominal type found
// Disallowed
fn in_method_generic_param_default<T = impl Debug>(_: T) {}
| ^^^^^^^^^^
error[E0562]: `impl Trait` not allowed outside of function and method return types
- --> $DIR/where-allowed.rs:240:40
+ --> $DIR/where-allowed.rs:241:40
|
LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
| ^^^^^^^^^^
error[E0562]: `impl Trait` not allowed outside of function and method return types
- --> $DIR/where-allowed.rs:246:29
+ --> $DIR/where-allowed.rs:247:29
|
LL | let _in_local_variable: impl Fn() = || {};
| ^^^^^^^^^
error[E0562]: `impl Trait` not allowed outside of function and method return types
- --> $DIR/where-allowed.rs:248:46
+ --> $DIR/where-allowed.rs:249:46
|
LL | let _in_return_in_local_variable = || -> impl Fn() { || {} };
| ^^^^^^^^^
= note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
- --> $DIR/where-allowed.rs:240:36
+ --> $DIR/where-allowed.rs:241:36
|
LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
| ^
= 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>
-error: aborting due to 48 previous errors
+error[E0118]: no nominal type found for inherent implementation
+ --> $DIR/where-allowed.rs:234:23
+ |
+LL | impl <T = impl Debug> T {}
+ | ^ impl requires a nominal type
+ |
+ = note: either implement a trait on it or create a newtype to wrap it instead
+
+error: aborting due to 49 previous errors
-Some errors have detailed explanations: E0562, E0658, E0666.
-For more information about an error, try `rustc --explain E0562`.
+Some errors have detailed explanations: E0118, E0562, E0658, E0666.
+For more information about an error, try `rustc --explain E0118`.
|
= note: `foo` must be defined only once in the value namespace of this module
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
--> $DIR/duplicate.rs:46:15
|
LL | use self::foo::bar;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `foo` could refer to the module imported here
--> $DIR/duplicate.rs:43:9
|
| ^^^^^^^^^^^
= help: consider adding an explicit import of `foo` to disambiguate
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
--> $DIR/duplicate.rs:35:8
|
LL | f::foo();
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `foo` could refer to the function imported here
--> $DIR/duplicate.rs:24:13
|
| ^^^^
= help: consider adding an explicit import of `foo` to disambiguate
-error[E0659]: `foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `foo` is ambiguous
--> $DIR/duplicate.rs:49:9
|
LL | foo::bar();
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `foo` could refer to the module imported here
--> $DIR/duplicate.rs:43:9
|
|
= note: this error originates in the macro `define_other_core` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `Vec` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `Vec` is ambiguous
--> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:13:9
|
LL | Vec::panic!();
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `Vec` could refer to the crate imported here
--> $DIR/extern-prelude-extern-crate-restricted-shadowing.rs:5:9
|
-error[E0659]: `env` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `env` is ambiguous
--> $DIR/glob-shadowing.rs:11:17
|
LL | let x = env!("PATH");
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
= note: `env` could refer to a macro from prelude
note: `env` could also refer to the macro imported here
--> $DIR/glob-shadowing.rs:9:9
= help: consider adding an explicit import of `env` to disambiguate
= help: or use `self::env` to refer to this macro unambiguously
-error[E0659]: `env` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `env` is ambiguous
--> $DIR/glob-shadowing.rs:19:21
|
LL | let x = env!("PATH");
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
= note: `env` could refer to a macro from prelude
note: `env` could also refer to the macro imported here
--> $DIR/glob-shadowing.rs:17:13
| ^^^^
= help: consider adding an explicit import of `env` to disambiguate
-error[E0659]: `fenv` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `fenv` is ambiguous
--> $DIR/glob-shadowing.rs:29:21
|
LL | let x = fenv!();
| ^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
note: `fenv` could refer to the macro imported here
--> $DIR/glob-shadowing.rs:27:13
|
LL | use nonexistent_module::mac;
| ^^^^^^^^^^^^^^^^^^ maybe a missing crate `nonexistent_module`?
-error[E0659]: `mac` is ambiguous (`macro_rules` vs non-`macro_rules` from other module)
+error[E0659]: `mac` is ambiguous
--> $DIR/issue-53269.rs:8:5
|
LL | mac!();
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module
note: `mac` could refer to the macro defined here
--> $DIR/issue-53269.rs:3:1
|
-error[E0659]: `S` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `S` is ambiguous
--> $DIR/issue-55884-1.rs:19:12
|
LL | use m::S;
| ^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `S` could refer to the struct imported here
--> $DIR/issue-55884-1.rs:14:13
|
LL | use empty::issue_56125;
| ^^^^^^^^^^^^^^^^^^ no `issue_56125` in `m3::empty`
-error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56125` is ambiguous
--> $DIR/issue-56125.rs:6:9
|
LL | use issue_56125::last_segment::*;
| ^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `issue_56125` could refer to a crate passed with `--extern`
= help: use `::issue_56125` to refer to this crate unambiguously
note: `issue_56125` could also refer to the module imported here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use `self::issue_56125` to refer to this module unambiguously
-error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56125` is ambiguous
--> $DIR/issue-56125.rs:11:9
|
LL | use issue_56125::non_last_segment::non_last_segment::*;
| ^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `issue_56125` could refer to a crate passed with `--extern`
= help: use `::issue_56125` to refer to this crate unambiguously
note: `issue_56125` could also refer to the module imported here
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use `self::issue_56125` to refer to this module unambiguously
-error[E0659]: `issue_56125` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56125` is ambiguous
--> $DIR/issue-56125.rs:18:9
|
LL | use issue_56125::*;
| ^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `issue_56125` could refer to a crate passed with `--extern`
= help: use `::issue_56125` to refer to this crate unambiguously
note: `issue_56125` could also refer to the module imported here
-error[E0659]: `core` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `core` is ambiguous
--> $DIR/issue-57539.rs:4:9
|
LL | use core;
| ^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `core` could refer to a built-in crate
= help: use `::core` to refer to this crate unambiguously
note: `core` could also refer to the module imported here
-error[E0659]: `exported` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `exported` is ambiguous
--> $DIR/local-modularized-tricky-fail-1.rs:28:1
|
LL | exported!();
| ^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `exported` could refer to the macro defined here
--> $DIR/local-modularized-tricky-fail-1.rs:5:5
|
= help: consider adding an explicit import of `exported` to disambiguate
= note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `exported` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `exported` is ambiguous
--> $DIR/local-modularized-tricky-fail-1.rs:28:1
|
LL | exported!();
| ^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `exported` could refer to the macro defined here
--> $DIR/local-modularized-tricky-fail-1.rs:5:5
|
= help: consider adding an explicit import of `exported` to disambiguate
= note: this error originates in the macro `define_exported` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
--> $DIR/local-modularized-tricky-fail-1.rs:36:5
|
LL | panic!();
| ^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
= note: `panic` could refer to a macro from prelude
note: `panic` could also refer to the macro defined here
--> $DIR/local-modularized-tricky-fail-1.rs:11:5
= help: use `crate::panic` to refer to this macro unambiguously
= note: this error originates in the macro `define_panic` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `include` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `include` is ambiguous
--> $DIR/local-modularized-tricky-fail-1.rs:47:1
|
LL | include!();
| ^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
= note: `include` could refer to a macro from prelude
note: `include` could also refer to the macro defined here
--> $DIR/local-modularized-tricky-fail-1.rs:17:5
-error[E0659]: `bar` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `bar` is ambiguous
--> $DIR/macro-paths.rs:13:5
|
LL | bar::m! {
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `bar` could refer to the module defined here
--> $DIR/macro-paths.rs:14:9
|
| ^^^^^^
= help: consider adding an explicit import of `bar` to disambiguate
-error[E0659]: `baz` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `baz` is ambiguous
--> $DIR/macro-paths.rs:23:5
|
LL | baz::m! {
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `baz` could refer to the module defined here
--> $DIR/macro-paths.rs:24:9
|
-error[E0659]: `m` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/macros.rs:16:5
|
LL | m! {
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `m` could refer to the macro imported here
--> $DIR/macros.rs:18:13
|
| ^^^^^^^^^^^^^
= help: consider adding an explicit import of `m` to disambiguate
-error[E0659]: `m` is ambiguous (glob import vs macro-expanded name in the same module during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/macros.rs:16:5
|
LL | m! {
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `m` could refer to the macro imported here
--> $DIR/macros.rs:18:13
|
| ^^^^^^^^^^^^^
= help: consider adding an explicit import of `m` to disambiguate
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/macros.rs:30:9
|
LL | m! {
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro imported here
--> $DIR/macros.rs:31:17
|
-error[E0659]: `Foo` is ambiguous (glob import vs glob import in the same module)
+error[E0659]: `Foo` is ambiguous
--> $DIR/rfc-1560-warning-cycle.rs:9:17
|
LL | fn f(_: Foo) {}
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple glob imports of a name in the same module
note: `Foo` could refer to the struct imported here
--> $DIR/rfc-1560-warning-cycle.rs:7:13
|
-error[E0659]: `panic` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:15:14
|
LL | fn f() { panic!(); }
| ^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
= note: `panic` could refer to a macro from prelude
note: `panic` could also refer to the macro imported here
--> $DIR/shadow_builtin_macros.rs:14:9
= help: consider adding an explicit import of `panic` to disambiguate
= help: or use `self::panic` to refer to this macro unambiguously
-error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:33:5
|
LL | panic!();
| ^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
= note: `panic` could refer to a macro from prelude
note: `panic` could also refer to the macro defined here
--> $DIR/shadow_builtin_macros.rs:30:9
| ---- in this macro invocation
= note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `n` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `n` is ambiguous
--> $DIR/shadow_builtin_macros.rs:49:5
|
LL | n!();
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
note: `n` could refer to the macro imported here
--> $DIR/shadow_builtin_macros.rs:48:9
|
LL | #[macro_use(n)]
| ^
-error[E0659]: `panic` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `panic` is ambiguous
--> $DIR/shadow_builtin_macros.rs:20:14
|
LL | fn f() { panic!(); }
| ^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
= note: `panic` could refer to a macro from prelude
note: `panic` could also refer to the macro imported here
--> $DIR/shadow_builtin_macros.rs:19:26
+++ /dev/null
-// run-pass
-
-#![allow(warnings)]
-#![feature(in_band_lifetimes)]
-
-fn foo(x: &'x u8) -> &'x u8 { x }
-fn foo2(x: &'a u8, y: &u8) -> &'a u8 { x }
-
-fn check_in_band_can_be_late_bound() {
- let _: for<'x> fn(&'x u8, &u8) -> &'x u8 = foo2;
-}
-
-struct ForInherentNoParams;
-
-impl ForInherentNoParams {
- fn foo(x: &'a u32, y: &u32) -> &'a u32 { x }
-}
-
-struct X<'a>(&'a u8);
-
-impl<'a> X<'a> {
- fn inner(&self) -> &'a u8 {
- self.0
- }
-
- fn same_lifetime_as_parameter(&mut self, x: &'a u8) {
- self.0 = x;
- }
-}
-
-impl X<'b> {
- fn inner_2(&self) -> &'b u8 {
- self.0
- }
-
- fn reference_already_introduced_in_band_from_method_with_explicit_binders<'a>(
- &'b self, x: &'a u32
- ) {}
-}
-
-struct Y<T>(T);
-
-impl Y<&'a u8> {
- fn inner(&self) -> &'a u8 {
- self.0
- }
-}
-
-trait MyTrait<'a> {
- fn my_lifetime(&self) -> &'a u8;
- fn any_lifetime() -> &'b u8;
- fn borrowed_lifetime(&'b self) -> &'b u8;
- fn default_impl(&self, x: &'b u32, y: &u32) -> &'b u32 { x }
- fn in_band_def_explicit_impl(&self, x: &'b u8);
-}
-
-impl MyTrait<'a> for Y<&'a u8> {
- fn my_lifetime(&self) -> &'a u8 { self.0 }
- fn any_lifetime() -> &'b u8 { &0 }
- fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
- fn in_band_def_explicit_impl<'b>(&self, x: &'b u8) {}
-}
-
-fn test_hrtb_defined_lifetime_where<F>(_: F) where for<'a> F: Fn(&'a u8) {}
-fn test_hrtb_defined_lifetime_polytraitref<F>(_: F) where F: for<'a> Fn(&'a u8) {}
-
-fn reference_in_band_from_locals(x: &'test u32) -> &'test u32 {
- let y: &'test u32 = x;
- y
-}
-
-fn in_generics_in_band<T: MyTrait<'a>>(x: &T) {}
-fn where_clause_in_band<T>(x: &T) where T: MyTrait<'a> {}
-fn impl_trait_in_band(x: &impl MyTrait<'a>) {}
-
-// Tests around using in-band lifetimes within existential traits.
-
-trait FunkyTrait<'a> { }
-impl<'a, T> FunkyTrait<'a> for T { }
-fn ret_pos_impl_trait_in_band_outlives(x: &'a u32) -> impl ::std::fmt::Debug + 'a {
- x
-}
-fn ret_pos_impl_trait_in_band_param(x: &'a u32) -> impl FunkyTrait<'a> {
- x
-}
-fn ret_pos_impl_trait_in_band_param_static(x: &'a u32) -> impl FunkyTrait<'static> + 'a {
- x
-}
-fn ret_pos_impl_trait_in_band_param_outlives(x: &'a u32) -> impl FunkyTrait<'a> + 'a {
- x
-}
-fn ret_pos_impl_trait_in_band_higher_ranked(x: &'a u32) -> impl for<'b> FunkyTrait<'b> + 'a {
- x
-}
-
-fn main() {}
--- /dev/null
+// run-pass
+
+#![allow(warnings)]
+#![feature(in_band_lifetimes)]
+
+fn foo(x: &'x u8) -> &'x u8 { x }
+fn foo2(x: &'a u8, y: &u8) -> &'a u8 { x }
+
+fn check_in_band_can_be_late_bound() {
+ let _: for<'x> fn(&'x u8, &u8) -> &'x u8 = foo2;
+}
+
+struct ForInherentNoParams;
+
+impl ForInherentNoParams {
+ fn foo(x: &'a u32, y: &u32) -> &'a u32 { x }
+}
+
+struct X<'a>(&'a u8);
+
+impl<'a> X<'a> {
+ fn inner(&self) -> &'a u8 {
+ self.0
+ }
+
+ fn same_lifetime_as_parameter(&mut self, x: &'a u8) {
+ self.0 = x;
+ }
+}
+
+impl X<'b> {
+ fn inner_2(&self) -> &'b u8 {
+ self.0
+ }
+
+ fn reference_already_introduced_in_band_from_method_with_explicit_binders<'a>(
+ &'b self, x: &'a u32
+ ) {}
+}
+
+struct Y<T>(T);
+
+impl Y<&'a u8> {
+ fn inner(&self) -> &'a u8 {
+ self.0
+ }
+}
+
+trait MyTrait<'a> {
+ fn my_lifetime(&self) -> &'a u8;
+ fn any_lifetime() -> &'b u8;
+ fn borrowed_lifetime(&'b self) -> &'b u8;
+ fn default_impl(&self, x: &'b u32, y: &u32) -> &'b u32 { x }
+ fn in_band_def_explicit_impl(&self, x: &'b u8);
+}
+
+impl MyTrait<'a> for Y<&'a u8> {
+ fn my_lifetime(&self) -> &'a u8 { self.0 }
+ fn any_lifetime() -> &'b u8 { &0 }
+ fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
+ fn in_band_def_explicit_impl<'b>(&self, x: &'b u8) {}
+}
+
+fn test_hrtb_defined_lifetime_where<F>(_: F) where for<'a> F: Fn(&'a u8) {}
+fn test_hrtb_defined_lifetime_polytraitref<F>(_: F) where F: for<'a> Fn(&'a u8) {}
+
+fn reference_in_band_from_locals(x: &'test u32) -> &'test u32 {
+ let y: &'test u32 = x;
+ y
+}
+
+fn in_generics_in_band<T: MyTrait<'a>>(x: &T) {}
+fn where_clause_in_band<T>(x: &T) where T: MyTrait<'a> {}
+fn impl_trait_in_band(x: &impl MyTrait<'a>) {}
+
+// Tests around using in-band lifetimes within existential traits.
+
+trait FunkyTrait<'a> { }
+impl<'a, T> FunkyTrait<'a> for T { }
+fn ret_pos_impl_trait_in_band_outlives(x: &'a u32) -> impl ::std::fmt::Debug + 'a {
+ x
+}
+fn ret_pos_impl_trait_in_band_param(x: &'a u32) -> impl FunkyTrait<'a> {
+ x
+}
+fn ret_pos_impl_trait_in_band_param_static(x: &'a u32) -> impl FunkyTrait<'static> + 'a {
+ x
+}
+fn ret_pos_impl_trait_in_band_param_outlives(x: &'a u32) -> impl FunkyTrait<'a> + 'a {
+ x
+}
+fn ret_pos_impl_trait_in_band_higher_ranked(x: &'a u32) -> impl for<'b> FunkyTrait<'b> + 'a {
+ x
+}
+
+fn main() {}
--- /dev/null
+// run-pass
+// Test for a specific corner case: when we compute the LUB of two fn
+// types and their parameters have unbound variables. In that case, we
+// wind up relating those two variables. This was causing an ICE in an
+// in-progress PR.
+
+fn main() {
+ let a_f: fn(_) = |_| ();
+ let b_f: fn(_) = |_| ();
+ let c_f = match 22 {
+ 0 => a_f,
+ _ => b_f,
+ };
+ c_f(4);
+}
--- /dev/null
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+pub fn todo<T>() -> T {
+ const { todo!() }
+}
+
+fn main() {
+ let _: usize = const { 0 };
+}
--- /dev/null
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+impl<'a> InvariantRef<'a, ()> {
+ pub const NEW: Self = InvariantRef::new(&());
+}
+
+fn equate<T>(x: T, y: T){}
+
+fn foo<'a>() {
+ let y = ();
+ equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
+ //~^ ERROR `y` does not live long enough [E0597]
+}
+
+fn main() {
+ foo();
+}
--- /dev/null
+error[E0597]: `y` does not live long enough
+ --> $DIR/const-expr-lifetime-err.rs:24:30
+ |
+LL | fn foo<'a>() {
+ | -- lifetime `'a` defined here
+LL | let y = ();
+LL | equate(InvariantRef::new(&y), const { InvariantRef::<'a>::NEW });
+ | ------------------^^-
+ | | |
+ | | borrowed value does not live long enough
+ | argument requires that `y` is borrowed for `'a`
+LL |
+LL | }
+ | - `y` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
+fn issue_78174() {
+ let foo = const { "foo" };
+ assert_eq!(foo, "foo");
+}
+
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+fn get_invariant_ref<'a>() -> InvariantRef<'a, ()> {
+ const { InvariantRef::<'a, ()>::new(&()) }
+}
+
+fn get_invariant_ref2<'a>() -> InvariantRef<'a, ()> {
+ // Try some type inference
+ const { InvariantRef::new(&()) }
+}
+
+fn main() {
+ issue_78174();
+ get_invariant_ref();
+ get_invariant_ref2();
+}
--- /dev/null
+// check-pass
+
+#![feature(inline_const)]
+#![allow(incomplete_features)]
+
+fn main() {
+ match 1u64 {
+ 0 => (),
+ const { 0 + 1 } => (),
+ const { 2 - 1 } ..= const { u64::MAX } => (),
+ }
+}
--- /dev/null
+// ignore-test
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+impl<'a> InvariantRef<'a, ()> {
+ pub const NEW: Self = InvariantRef::new(&());
+}
+
+fn match_invariant_ref<'a>() {
+ let y = ();
+ match InvariantRef::new(&y) {
+ //~^ ERROR `y` does not live long enough [E0597]
+ // FIXME(nbdd0121): This should give the same error as `InvariantRef::<'a>::NEW` (without
+ // const block)
+ const { InvariantRef::<'a>::NEW } => (),
+ }
+}
+
+fn main() {
+ match_invariant_ref();
+}
--- /dev/null
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(inline_const)]
+
+use std::marker::PhantomData;
+
+// rust-lang/rust#78174: ICE: "cannot convert ReErased to a region vid"
+fn issue_78174() {
+ match "foo" {
+ const { concat!("fo", "o") } => (),
+ _ => unreachable!(),
+ }
+}
+
+#[derive(PartialEq, Eq)]
+pub struct InvariantRef<'a, T: ?Sized>(&'a T, PhantomData<&'a mut &'a T>);
+
+impl<'a, T: ?Sized> InvariantRef<'a, T> {
+ pub const fn new(r: &'a T) -> Self {
+ InvariantRef(r, PhantomData)
+ }
+}
+
+fn match_invariant_ref<'a>() {
+ match const { InvariantRef::<'a, _>::new(&()) } {
+ const { InvariantRef::<'a, ()>::new(&()) } => {
+ }
+ }
+}
+
+fn main() {
+ issue_78174();
+ match_invariant_ref();
+}
//~^ ERROR expected a `FnOnce<()>` closure
const_eval_select((), 42, 0xDEADBEEF);
//~^ ERROR expected a `FnOnce<()>` closure
+ //~| ERROR expected a `FnOnce<()>` closure
}
const fn foo(n: i32) -> i32 {
error[E0277]: expected a `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
- --> $DIR/const-eval-select-bad.rs:6:34
+ --> $DIR/const-eval-select-bad.rs:6:27
|
LL | const_eval_select((), || {}, || {});
- | ----------------- ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
+ | ----------------- ^^^^^ expected an `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
| |
| required by a bound introduced by this call
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
- --> $DIR/const-eval-select-bad.rs:8:31
+ --> $DIR/const-eval-select-bad.rs:8:27
|
LL | const_eval_select((), 42, 0xDEADBEEF);
- | ----------------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}`
+ | ----------------- ^^ expected an `FnOnce<()>` closure, found `{integer}`
| |
| required by a bound introduced by this call
|
LL | F: ~const FnOnce<ARG, Output = RET>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
+ --> $DIR/const-eval-select-bad.rs:8:31
+ |
+LL | const_eval_select((), 42, 0xDEADBEEF);
+ | ----------------- ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `{integer}`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the trait `FnOnce<()>` is not implemented for `{integer}`
+ = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
+note: required by a bound in `const_eval_select`
+ --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
+ |
+LL | G: FnOnce<ARG, Output = RET> + ~const Drop,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
+
error[E0271]: type mismatch resolving `<fn(i32) -> bool {bar} as FnOnce<(i32,)>>::Output == i32`
- --> $DIR/const-eval-select-bad.rs:27:5
+ --> $DIR/const-eval-select-bad.rs:28:5
|
LL | const_eval_select((1,), foo, bar);
| ^^^^^^^^^^^^^^^^^ expected `i32`, found `bool`
| ^^^^^^^^^^^^ required by this bound in `const_eval_select`
error[E0631]: type mismatch in function arguments
- --> $DIR/const-eval-select-bad.rs:32:37
+ --> $DIR/const-eval-select-bad.rs:33:32
|
LL | const fn foo(n: i32) -> i32 {
| --------------------------- found signature of `fn(i32) -> _`
...
LL | const_eval_select((true,), foo, baz);
- | ----------------- ^^^ expected signature of `fn(bool) -> _`
+ | ----------------- ^^^ expected signature of `fn(bool) -> _`
| |
| required by a bound introduced by this call
|
LL | F: ~const FnOnce<ARG, Output = RET>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
Some errors have detailed explanations: E0271, E0277, E0631.
For more information about an error, try `rustc --explain E0271`.
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "illumos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
+++ /dev/null
-#![crate_type = "lib"]
-
-#[macro_export]
-macro_rules! mywrite {
- ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*)))
-}
+++ /dev/null
-#![crate_type="rlib"]
-
-#[derive(Debug, PartialEq)]
-pub struct RemoteC(pub u32);
-
-#[derive(Debug, PartialEq)]
-pub struct RemoteG<T>(pub T);
+++ /dev/null
-#![crate_type="lib"]
-
-
-pub trait A {
- fn a(&self) {}
-}
-impl A for () {}
+++ /dev/null
-#![crate_type="lib"]
-
-pub extern crate xcrate_issue_43189_a;
+++ /dev/null
-#![crate_type="lib"]
-
-pub extern crate core;
+++ /dev/null
-// edition:2018
-#![crate_type="lib"]
-#![crate_name="xcrate_issue_61711_b"]
-pub struct Struct;
-pub use crate as alias;
+++ /dev/null
-#![feature(box_syntax)]
-
-fn main() {
- let x: Box<_> = box 1;
- let f = move|| {
- let _a = x;
- drop(x);
- //~^ ERROR: use of moved value: `x`
- };
- f();
-}
+++ /dev/null
-error[E0382]: use of moved value: `x`
- --> $DIR/issue-10398.rs:7:14
- |
-LL | let _a = x;
- | - value moved here
-LL | drop(x);
- | ^ value used here after move
- |
- = note: move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0382`.
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-// Issue #1112
-// Alignment of interior pointers to dynamic-size types
-
-
-struct X<T> {
- a: T,
- b: u8,
- c: bool,
- d: u8,
- e: u16,
- f: u8,
- g: u8
-}
-
-pub fn main() {
- let x: X<isize> = X {
- a: 12345678,
- b: 9,
- c: true,
- d: 10,
- e: 11,
- f: 12,
- g: 13
- };
- bar(x);
-}
-
-fn bar<T>(x: X<T>) {
- assert_eq!(x.b, 9);
- assert_eq!(x.c, true);
- assert_eq!(x.d, 10);
- assert_eq!(x.e, 11);
- assert_eq!(x.f, 12);
- assert_eq!(x.g, 13);
-}
+++ /dev/null
-// run-pass
-// Destructuring struct variants would ICE where regular structs wouldn't
-
-enum Foo {
- VBar { num: isize }
-}
-
-struct SBar { num: isize }
-
-pub fn main() {
- let vbar = Foo::VBar { num: 1 };
- let Foo::VBar { num } = vbar;
- assert_eq!(num, 1);
-
- let sbar = SBar { num: 2 };
- let SBar { num } = sbar;
- assert_eq!(num, 2);
-}
+++ /dev/null
-// run-pass
-
-const TEST_STR: &'static str = "abcd";
-
-fn main() {
- let s = "abcd";
- match s {
- TEST_STR => (),
- _ => unreachable!()
- }
-}
+++ /dev/null
-trait Trait {
- fn outer(&self) {
- fn inner(_: &Self) {
- //~^ ERROR can't use generic parameters from outer function
- }
- }
-}
-
-fn main() { }
+++ /dev/null
-error[E0401]: can't use generic parameters from outer function
- --> $DIR/issue-12796.rs:3:22
- |
-LL | fn inner(_: &Self) {
- | ^^^^
- | |
- | use of generic parameter from outer function
- | can't use `Self` here
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0401`.
+++ /dev/null
-fn main() {
- if true {
- } else if { //~ ERROR missing condition
- //~^ ERROR mismatched types
- } else {
- }
-}
-
-fn foo() {
- if true {
- } else if { //~ ERROR missing condition
- //~^ ERROR mismatched types
- }
- bar();
-}
-
-fn bar() {}
+++ /dev/null
-error: missing condition for `if` expression
- --> $DIR/issue-13483.rs:3:14
- |
-LL | } else if {
- | ^ expected if condition here
-
-error: missing condition for `if` expression
- --> $DIR/issue-13483.rs:11:14
- |
-LL | } else if {
- | ^ expected if condition here
-
-error[E0308]: mismatched types
- --> $DIR/issue-13483.rs:3:15
- |
-LL | } else if {
- | _______________^
-LL | |
-LL | | } else {
- | |_____^ expected `bool`, found `()`
-
-error[E0308]: mismatched types
- --> $DIR/issue-13483.rs:11:15
- |
-LL | } else if {
- | _______________^
-LL | |
-LL | | }
- | |_____^ expected `bool`, found `()`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-#![allow(non_camel_case_types)]
-
-const JSVAL_TAG_CLEAR: u32 = 0xFFFFFF80;
-const JSVAL_TYPE_INT32: u8 = 0x01;
-const JSVAL_TYPE_UNDEFINED: u8 = 0x02;
-#[repr(u32)]
-enum ValueTag {
- JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | (JSVAL_TYPE_INT32 as u32),
- JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | (JSVAL_TYPE_UNDEFINED as u32),
-}
-
-fn main() {
- let _ = ValueTag::JSVAL_TAG_INT32;
-}
+++ /dev/null
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-14227.rs:7:21
- |
-LL | static CRASH: u32 = symbol;
- | ^^^^^^ use of extern static
- |
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-// revisions: mir thir
-// [thir]compile-flags: -Z thir-unsafeck
-
-extern "C" {
- pub static symbol: u32;
-}
-static CRASH: u32 = symbol;
-//~^ ERROR use of extern static is unsafe and requires
-
-fn main() {}
+++ /dev/null
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-14227.rs:7:21
- |
-LL | static CRASH: u32 = symbol;
- | ^^^^^^ use of extern static
- |
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-// run-pass
-#![allow(unused_mut)]
-// ignore-emscripten no processes
-// ignore-sgx no processes
-
-use std::env;
-use std::io::prelude::*;
-use std::io;
-use std::process::{Command, Stdio};
-
-fn main() {
- let args: Vec<String> = env::args().collect();
- if args.len() > 1 && args[1] == "child" {
- return child()
- }
-
- test();
-}
-
-fn child() {
- writeln!(&mut io::stdout(), "foo").unwrap();
- writeln!(&mut io::stderr(), "bar").unwrap();
- let mut stdin = io::stdin();
- let mut s = String::new();
- stdin.lock().read_line(&mut s).unwrap();
- assert_eq!(s.len(), 0);
-}
-
-fn test() {
- let args: Vec<String> = env::args().collect();
- let mut p = Command::new(&args[0]).arg("child")
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .stderr(Stdio::piped())
- .spawn().unwrap();
- assert!(p.wait().unwrap().success());
-}
+++ /dev/null
-// run-pass
-// All 3 expressions should work in that the argument gets
-// coerced to a trait object
-
-// pretty-expanded FIXME #23616
-
-fn main() {
- send::<Box<dyn Foo>>(Box::new(Output(0)));
- Test::<Box<dyn Foo>>::foo(Box::new(Output(0)));
- Test::<Box<dyn Foo>>::new().send(Box::new(Output(0)));
-}
-
-fn send<T>(_: T) {}
-
-struct Test<T> { marker: std::marker::PhantomData<T> }
-impl<T> Test<T> {
- fn new() -> Test<T> { Test { marker: ::std::marker::PhantomData } }
- fn foo(_: T) {}
- fn send(&self, _: T) {}
-}
-
-trait Foo { fn dummy(&self) { }}
-struct Output(isize);
-impl Foo for Output {}
+++ /dev/null
-// check-pass
-// pretty-expanded FIXME #23616
-
-#[deny(dead_code)]
-pub enum Foo {
- Bar {
- baz: isize
- }
-}
-
-fn main() { }
+++ /dev/null
-// run-pass
-
-fn main() {
- let mut x: &[_] = &[1, 2, 3, 4];
-
- let mut result = vec![];
- loop {
- x = match *x {
- [1, n, 3, ref rest @ ..] => {
- result.push(n);
- rest
- }
- [n, ref rest @ ..] => {
- result.push(n);
- rest
- }
- [] =>
- break
- }
- }
- assert_eq!(result, [2, 4]);
-}
+++ /dev/null
-macro_rules! prob1 {
- (0) => {
- 0
- };
- ($n:expr) => {
- if ($n % 3 == 0) || ($n % 5 == 0) {
- $n + prob1!($n - 1); //~ ERROR recursion limit reached while expanding `prob1!`
- } else {
- prob1!($n - 1);
- }
- };
-}
-
-fn main() {
- println!("Problem 1: {}", prob1!(1000));
-}
+++ /dev/null
-error: recursion limit reached while expanding `prob1!`
- --> $DIR/issue-16098.rs:7:18
- |
-LL | $n + prob1!($n - 1);
- | ^^^^^^^^^^^^^^
-...
-LL | println!("Problem 1: {}", prob1!(1000));
- | ------------ in this macro invocation
- |
- = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_16098`)
- = note: this error originates in the macro `prob1` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-// ignore-emscripten no processes
-// ignore-sgx no processes
-
-use std::process::Command;
-use std::env;
-
-fn main() {
- let len = env::args().len();
-
- if len == 1 {
- test();
- } else {
- assert_eq!(len, 3);
- }
-}
-
-fn test() {
- let status = Command::new(&env::current_exe().unwrap())
- .arg("foo").arg("")
- .status().unwrap();
- assert!(status.success());
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-
-static X2: u64 = !0 as u16 as u64;
-static Y2: u64 = !0 as u32 as u64;
-const X: u64 = !0 as u16 as u64;
-const Y: u64 = !0 as u32 as u64;
-
-fn main() {
- assert_eq!(match 1 {
- X => unreachable!(),
- Y => unreachable!(),
- _ => 1
- }, 1);
-}
+++ /dev/null
-// run-pass
-// Regression test for #18060: match arms were matching in the wrong order.
-
-fn main() {
- assert_eq!(2, match (1, 3) { (0, 2..=5) => 1, (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 });
- assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 });
- assert_eq!(2, match (1, 7) { (0, 2..=5) => 1, (1, 7) => 2, (_, 2..=5) => 3, (_, _) => 4 });
-}
+++ /dev/null
-fn main() {
- const X: u32 = 1;
- const Y: usize = unsafe { &X as *const u32 as usize }; //~ ERROR pointers cannot be cast to integers
- println!("{}", Y);
-}
+++ /dev/null
-error: pointers cannot be cast to integers during const eval
- --> $DIR/issue-18294.rs:3:31
- |
-LL | const Y: usize = unsafe { &X as *const u32 as usize };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: at compile-time, pointers do not have an integer value
- = note: avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-// Tests multiple free variables being passed by value into an unboxed
-// once closure as an optimization by codegen. This used to hit an
-// incorrect assert.
-
-fn main() {
- let x = 2u8;
- let y = 3u8;
- assert_eq!((move || x + y)(), 5);
-}
+++ /dev/null
-// aux-build:issue-19163.rs
-
-#[macro_use] extern crate issue_19163;
-
-use std::io::Write;
-
-fn main() {
- let mut v = vec![];
- mywrite!(&v, "Hello world");
- //~^ ERROR cannot borrow data in a `&` reference as mutable
-}
+++ /dev/null
-error[E0596]: cannot borrow data in a `&` reference as mutable
- --> $DIR/issue-19163.rs:9:5
- |
-LL | mywrite!(&v, "Hello world");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
- |
- = note: this error originates in the macro `mywrite` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0596`.
+++ /dev/null
-// run-pass
-
-#![allow(dead_code)]
-
-trait Trait { fn dummy(&self) { } }
-
-#[derive(Debug)]
-struct Foo<T: Trait> {
- foo: T,
-}
-
-#[derive(Debug)]
-struct Bar<T> where T: Trait {
- bar: T,
-}
-
-impl Trait for isize {}
-
-fn main() {
- let a = Foo { foo: 12 };
- let b = Bar { bar: 12 };
- println!("{:?} {:?}", a, b);
-}
+++ /dev/null
-// error-pattern: requires `copy` lang_item
-
-#![feature(lang_items, start, no_core)]
-#![no_core]
-
-#[lang = "sized"]
-trait Sized { }
-
-struct S;
-
-#[start]
-fn main(_: isize, _: *const *const u8) -> isize {
- let _ = S;
- 0
-}
+++ /dev/null
-error: requires `copy` lang_item
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-#![allow(stable_features)]
-
-// ignore-emscripten no processes
-// ignore-sgx no processes
-
-#![feature(os)]
-
-#[cfg(unix)]
-fn main() {
- use std::process::Command;
- use std::env;
- use std::os::unix::prelude::*;
- use std::ffi::OsStr;
-
- if env::args().len() == 1 {
- assert!(Command::new(&env::current_exe().unwrap())
- .arg(<OsStr as OsStrExt>::from_bytes(b"\xff"))
- .status().unwrap().success())
- }
-}
-
-#[cfg(windows)]
-fn main() {}
+++ /dev/null
-// We need all these 9 issue-20616-N.rs files
-// because we can only catch one parsing error at a time
-
-type Type_1_<'a, T> = &'a T;
-
-
-//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
-
-
-//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
-
-
-//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
-
-
-type Type_4<T> = Type_1_<'static,, T>;
-//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
-
-
-type Type_5_<'a> = Type_1_<'a, ()>;
-
-
-//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
-
-
-//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
-
-
-//type Type_7 = Box<(),,>; // error: expected type, found `,`
-
-
-//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
-
-
-//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
+++ /dev/null
-error: expected one of `>`, a const expression, lifetime, or type, found `,`
- --> $DIR/issue-20616-4.rs:16:34
- |
-LL | type Type_4<T> = Type_1_<'static,, T>;
- | ^ expected one of `>`, a const expression, lifetime, or type
-
-error: aborting due to previous error
-
+++ /dev/null
-// We need all these 9 issue-20616-N.rs files
-// because we can only catch one parsing error at a time
-
-type Type_1_<'a, T> = &'a T;
-
-
-//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
-
-
-//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
-
-
-//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
-
-
-//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
-
-
-type Type_5_<'a> = Type_1_<'a, ()>;
-
-
-type Type_5<'a> = Type_1_<'a, (),,>;
-//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
-
-
-//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
-
-
-//type Type_7 = Box<(),,>; // error: expected type, found `,`
-
-
-//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
-
-
-//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
+++ /dev/null
-error: expected one of `>`, a const expression, lifetime, or type, found `,`
- --> $DIR/issue-20616-5.rs:22:34
- |
-LL | type Type_5<'a> = Type_1_<'a, (),,>;
- | ^ expected one of `>`, a const expression, lifetime, or type
-
-error: aborting due to previous error
-
+++ /dev/null
-// We need all these 9 issue-20616-N.rs files
-// because we can only catch one parsing error at a time
-
-type Type_1_<'a, T> = &'a T;
-
-
-//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
-
-
-//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
-
-
-//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
-
-
-//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
-
-
-type Type_5_<'a> = Type_1_<'a, ()>;
-
-
-//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
-
-
-type Type_6 = Type_5_<'a,,>;
-//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
-
-
-//type Type_7 = Box<(),,>; // error: expected type, found `,`
-
-
-//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
-
-
-//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
+++ /dev/null
-error: expected one of `>`, a const expression, lifetime, or type, found `,`
- --> $DIR/issue-20616-6.rs:25:26
- |
-LL | type Type_6 = Type_5_<'a,,>;
- | ^ expected one of `>`, a const expression, lifetime, or type
-
-error: aborting due to previous error
-
+++ /dev/null
-// We need all these 9 issue-20616-N.rs files
-// because we can only catch one parsing error at a time
-
-type Type_1_<'a, T> = &'a T;
-
-
-//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
-
-
-//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
-
-
-//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
-
-
-//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
-
-
-type Type_5_<'a> = Type_1_<'a, ()>;
-
-
-//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
-
-
-//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
-
-
-type Type_7 = Box<(),,>;
-//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
-
-
-//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
-
-
-//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
+++ /dev/null
-error: expected one of `>`, a const expression, lifetime, or type, found `,`
- --> $DIR/issue-20616-7.rs:28:22
- |
-LL | type Type_7 = Box<(),,>;
- | ^ expected one of `>`, a const expression, lifetime, or type
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-// compile-flags: --test
-
-#[test]
-pub fn foo() {}
+++ /dev/null
-#![allow(unused_macros)]
-
-macro_rules! test { ($wrong:t_ty ..) => () }
- //~^ ERROR: invalid fragment specifier `t_ty`
-
-fn main() {}
+++ /dev/null
-error: invalid fragment specifier `t_ty`
- --> $DIR/issue-21356.rs:3:22
- |
-LL | macro_rules! test { ($wrong:t_ty ..) => () }
- | ^^^^^^^^^^^
- |
- = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-pass
-#![allow(unused_imports, overlapping_range_endpoints)]
-// pretty-expanded FIXME #23616
-
-use m::{START, END};
-
-fn main() {
- match 42 {
- m::START..=m::END => {},
- 0..=m::END => {},
- m::START..=59 => {},
- _ => {},
- }
-}
-
-mod m {
- pub const START: u32 = 4;
- pub const END: u32 = 14;
-}
+++ /dev/null
-// check-pass
-#![allow(dead_code)]
-// Test that the requirement (in `Bar`) that `T::Bar : 'static` does
-// not wind up propagating to `T`.
-
-// pretty-expanded FIXME #23616
-
-pub trait Foo {
- type Bar;
-
- fn foo(&self) -> Self;
-}
-
-pub struct Static<T:'static>(T);
-
-struct Bar<T:Foo>
- where T::Bar : 'static
-{
- x: Static<Option<T::Bar>>
-}
-
-fn main() { }
+++ /dev/null
-// check-pass
-pub trait LineFormatter<'a> {
- type Iter: Iterator<Item=&'a str> + 'a;
- fn iter(&'a self, line: &'a str) -> Self::Iter;
-
- fn dimensions(&'a self, line: &'a str) {
- let iter: Self::Iter = self.iter(line);
- <_ as IntoIterator>::into_iter(iter);
- }
-}
-
-fn main() {}
+++ /dev/null
-// run-pass
-macro_rules! items {
- () => {
- type A = ();
- fn a() {}
- }
-}
-
-trait Foo {
- type A;
- fn a();
-}
-
-impl Foo for () {
- items!();
-}
-
-fn main() {
-
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-// Test transitive analysis for associated types. Collected types
-// should be normalized and new obligations generated.
-
-// pretty-expanded FIXME #23616
-
-trait Foo {
- type A;
- fn foo(&self) {}
-}
-
-impl Foo for usize {
- type A = usize;
-}
-
-struct Bar<T: Foo> { inner: T::A }
-
-fn is_send<T: Send>() {}
-
-fn main() {
- is_send::<Bar<usize>>();
-}
+++ /dev/null
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-// compile-flags: -Ccodegen-units=1
-// build-fail
-// only-x86_64
-
-fn main() {
- unsafe {
- llvm_asm!("int $3"); //~ ERROR too few operands for instruction
- //~| ERROR invalid operand in inline asm
- }
-}
+++ /dev/null
-error: invalid operand in inline asm: 'int $3'
- --> $DIR/issue-23458.rs:9:9
- |
-LL | llvm_asm!("int $3");
- | ^
-
-error: too few operands for instruction
- --> $DIR/issue-23458.rs:9:9
- |
-LL | llvm_asm!("int $3");
- | ^
- |
-note: instantiated into assembly here
- --> <inline asm>:1:2
- |
-LL | int
- | ^
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-static foo: i32 = 0;
-
-fn bar(foo: i32) {}
-//~^ ERROR function parameters cannot shadow statics
-//~| cannot be named the same as a static
-
-mod submod {
- pub static answer: i32 = 42;
-}
-
-use self::submod::answer;
-
-fn question(answer: i32) {}
-//~^ ERROR function parameters cannot shadow statics
-//~| cannot be named the same as a static
-fn main() {
-}
+++ /dev/null
-error[E0530]: function parameters cannot shadow statics
- --> $DIR/issue-23716.rs:3:8
- |
-LL | static foo: i32 = 0;
- | -------------------- the static `foo` is defined here
-LL |
-LL | fn bar(foo: i32) {}
- | ^^^ cannot be named the same as a static
-
-error[E0530]: function parameters cannot shadow statics
- --> $DIR/issue-23716.rs:13:13
- |
-LL | use self::submod::answer;
- | -------------------- the static `answer` is imported here
-LL |
-LL | fn question(answer: i32) {}
- | ^^^^^^ cannot be named the same as a static
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0530`.
+++ /dev/null
-// run-pass
-const U8_MAX_HALF: u8 = !0u8 / 2;
-const U16_MAX_HALF: u16 = !0u16 / 2;
-const U32_MAX_HALF: u32 = !0u32 / 2;
-const U64_MAX_HALF: u64 = !0u64 / 2;
-
-fn main() {
- assert_eq!(U8_MAX_HALF, 0x7f);
- assert_eq!(U16_MAX_HALF, 0x7fff);
- assert_eq!(U32_MAX_HALF, 0x7fff_ffff);
- assert_eq!(U64_MAX_HALF, 0x7fff_ffff_ffff_ffff);
-}
+++ /dev/null
-// run-pass
-
-trait Foo: Fn(i32) -> i32 + Send {}
-
-impl<T: ?Sized + Fn(i32) -> i32 + Send> Foo for T {}
-
-fn wants_foo(f: Box<dyn Foo>) -> i32 {
- f(42)
-}
-
-fn main() {
- let f = Box::new(|x| x);
- assert_eq!(wants_foo(f), 42);
-}
+++ /dev/null
-// run-pass
-// ignore-emscripten no threads
-// ignore-sgx no processes
-
-use std::thread;
-use std::env;
-use std::process::Command;
-
-struct Handle(i32);
-
-impl Drop for Handle {
- fn drop(&mut self) { panic!(); }
-}
-
-thread_local!(static HANDLE: Handle = Handle(0));
-
-fn main() {
- let args = env::args().collect::<Vec<_>>();
- if args.len() == 1 {
- let out = Command::new(&args[0]).arg("test").output().unwrap();
- let stderr = std::str::from_utf8(&out.stderr).unwrap();
- assert!(stderr.contains("panicked at 'explicit panic'"),
- "bad failure message:\n{}\n", stderr);
- } else {
- // TLS dtors are not always run on process exit
- thread::spawn(|| {
- HANDLE.with(|h| {
- println!("{}", h.0);
- });
- }).join().unwrap();
- }
-}
+++ /dev/null
-// run-fail
-// error-pattern:explicit panic
-// ignore-emscripten no processes
-
-use std::sync::Arc;
-
-enum Err<T> {
- Errr(Arc<T>),
-}
-
-fn foo() -> Err<isize> {
- panic!();
-}
-
-fn main() {
- let _f = foo();
-}
+++ /dev/null
-// run-pass
-#![allow(overlapping_range_endpoints)]
-
-fn main() {
- let x = 'a';
-
- let y = match x {
- 'a'..='b' if false => "one",
- 'a' => "two",
- 'a'..='b' => "three",
- _ => panic!("what?"),
- };
-
- assert_eq!(y, "two");
-}
+++ /dev/null
-// run-pass
-
-pub trait Foo<T> {
- fn foo(self) -> T;
-}
-
-impl<'a, T> Foo<T> for &'a str where &'a str: Into<T> {
- fn foo(self) -> T {
- panic!();
- }
-}
-
-fn main() {}
+++ /dev/null
-// check-pass
-
-pub struct Bar<T> {
- items: Vec<&'static str>,
- inner: T,
-}
-
-pub trait IntoBar<T> {
- fn into_bar(self) -> Bar<T>;
-}
-
-impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> {
- fn into_bar(self) -> Bar<T> {
- Bar {
- items: Vec::new(),
- inner: self.into(),
- }
- }
-}
-
-fn main() {}
+++ /dev/null
-// check-pass
-
-pub struct Item {
- _inner: &'static str,
-}
-
-pub struct Bar<T> {
- items: Vec<Item>,
- inner: T,
-}
-
-pub trait IntoBar<T> {
- fn into_bar(self) -> Bar<T>;
-}
-
-impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> {
- fn into_bar(self) -> Bar<T> {
- Bar {
- items: Vec::new(),
- inner: self.into(),
- }
- }
-}
-
-fn main() {}
+++ /dev/null
-fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
-//~^ ERROR missing lifetime specifier [E0106]
-
-fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
-//~^ ERROR missing lifetime specifier [E0106]
-
-fn parse_type_3() -> &str { unimplemented!() }
-//~^ ERROR missing lifetime specifier [E0106]
-
-fn main() {}
+++ /dev/null
-error[E0106]: missing lifetime specifier
- --> $DIR/issue-26638.rs:1:62
- |
-LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
- | ------------------------------------ ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from
-help: consider introducing a named lifetime parameter
- |
-LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'a str { iter.next() }
- | ++++ ++
-
-error[E0106]: missing lifetime specifier
- --> $DIR/issue-26638.rs:4:40
- |
-LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
- | ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
-help: consider using the `'static` lifetime
- |
-LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() }
- | ~~~~~~~~
-
-error[E0106]: missing lifetime specifier
- --> $DIR/issue-26638.rs:7:22
- |
-LL | fn parse_type_3() -> &str { unimplemented!() }
- | ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
-help: consider using the `'static` lifetime
- |
-LL | fn parse_type_3() -> &'static str { unimplemented!() }
- | ~~~~~~~~
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0106`.
+++ /dev/null
-// run-pass
-
-// This test is bogus (i.e., should be check-fail) during the period
-// where #54986 is implemented and #54987 is *not* implemented. For
-// now: just ignore it
-//
-// ignore-test
-
-// This test is checking that the write to `c.0` (which has been moved out of)
-// won't overwrite the state in `c2`.
-//
-// That's a fine thing to test when this code is accepted by the
-// compiler, and this code is being transcribed accordingly into
-// the ui test issue-21232-partial-init-and-use.rs
-
-fn main() {
- let mut c = (1, "".to_owned());
- match c {
- c2 => {
- c.0 = 2;
- assert_eq!(c2.0, 1);
- }
- }
-}
+++ /dev/null
-// run-pass
-
-fn thing<'r>(x: &'r [isize]) -> &'r [isize] { x }
-
-pub fn main() {
- let x = &[1,2,3];
- let y = x;
- let z = thing(x);
- assert_eq!(z[2], x[2]);
- assert_eq!(z[1], y[1]);
-}
+++ /dev/null
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-28324.rs:8:24
- |
-LL | pub static BAZ: u32 = *&error_message_count;
- | ^^^^^^^^^^^^^^^^^^^^ use of extern static
- |
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-// revisions: mir thir
-// [thir]compile-flags: -Z thir-unsafeck
-
-extern "C" {
- static error_message_count: u32;
-}
-
-pub static BAZ: u32 = *&error_message_count;
-//~^ ERROR use of extern static is unsafe and requires
-
-fn main() {}
+++ /dev/null
-error[E0133]: use of extern static is unsafe and requires unsafe function or block
- --> $DIR/issue-28324.rs:8:25
- |
-LL | pub static BAZ: u32 = *&error_message_count;
- | ^^^^^^^^^^^^^^^^^^^ use of extern static
- |
- = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0133`.
+++ /dev/null
-// run-pass
-
-// Demonstrate the use of the unguarded escape hatch with a type param in negative position
-// to assert that destructor will not access any dead data.
-//
-// Compare with ui/span/issue28498-reject-lifetime-param.rs
-
-// Demonstrate that a type param in negative position causes dropck to reject code
-// that might indirectly access previously dropped value.
-//
-// Compare with run-pass/issue28498-ugeh-with-passed-to-fn.rs
-
-#![feature(dropck_eyepatch)]
-
-#[derive(Debug)]
-struct ScribbleOnDrop(String);
-
-impl Drop for ScribbleOnDrop {
- fn drop(&mut self) {
- self.0 = format!("DROPPED");
- }
-}
-
-struct Foo<T>(u32, T, Box<for <'r> fn(&'r T) -> String>);
-
-unsafe impl<#[may_dangle] T> Drop for Foo<T> {
- fn drop(&mut self) {
- // Use of `may_dangle` is sound, because destructor never passes a `self.1`
- // to the callback (in `self.2`) despite having it available.
- println!("Dropping Foo({}, _)", self.0);
- }
-}
-
-fn callback(s: & &ScribbleOnDrop) -> String { format!("{:?}", s) }
-
-fn main() {
- let (last_dropped, foo0);
- let (foo1, first_dropped);
-
- last_dropped = ScribbleOnDrop(format!("last"));
- first_dropped = ScribbleOnDrop(format!("first"));
- foo0 = Foo(0, &last_dropped, Box::new(callback));
- foo1 = Foo(1, &first_dropped, Box::new(callback));
-
- println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
-}
+++ /dev/null
-// check-pass
-// Regression test for #28871. The problem is that rustc encountered
-// two ways to project, one from a where clause and one from the where
-// clauses on the trait definition. (In fact, in this case, the where
-// clauses originated from the trait definition as well.) The true
-// cause of the error is that the trait definition where clauses are
-// not being normalized, and hence the two sources are considered in
-// conflict, and not a duplicate. Hacky solution is to prefer where
-// clauses over the data found in the trait definition.
-
-trait T {
- type T;
-}
-
-struct S;
-impl T for S {
- type T = S;
-}
-
-trait T2 {
- type T: Iterator<Item=<S as T>::T>;
-}
-
-fn main() { }
+++ /dev/null
-macro_rules! foo {
- ($d:expr) => {{
- fn bar(d: u8) { }
- bar(&mut $d);
- //~^ ERROR mismatched types
- //~| expected `u8`, found `&mut u8`
- }}
-}
-
-fn main() {
- foo!(0u8);
- //~^ in this expansion of foo!
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-29084.rs:4:13
- |
-LL | bar(&mut $d);
- | ^^^^^^^ expected `u8`, found `&mut u8`
-...
-LL | foo!(0u8);
- | --------- in this macro invocation
- |
- = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-fn siphash<T>() {
-
- trait U {
- fn g(&self, x: T) -> T; //~ ERROR can't use generic parameters from outer function
- //~^ ERROR can't use generic parameters from outer function
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0401]: can't use generic parameters from outer function
- --> $DIR/issue-3021-c.rs:4:24
- |
-LL | fn siphash<T>() {
- | - type parameter from outer function
-...
-LL | fn g(&self, x: T) -> T;
- | - ^ use of generic parameter from outer function
- | |
- | help: try using a local generic parameter instead: `g<T>`
-
-error[E0401]: can't use generic parameters from outer function
- --> $DIR/issue-3021-c.rs:4:30
- |
-LL | fn siphash<T>() {
- | - type parameter from outer function
-...
-LL | fn g(&self, x: T) -> T;
- | - ^ use of generic parameter from outer function
- | |
- | help: try using a local generic parameter instead: `g<T>`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0401`.
+++ /dev/null
-trait SipHash {
- fn reset(&self);
-}
-
-fn siphash(k0 : u64) {
- struct SipState {
- v0: u64,
- }
-
- impl SipHash for SipState {
- fn reset(&self) {
- self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR can't capture dynamic environment
- }
- }
- panic!();
-}
-
-fn main() {}
+++ /dev/null
-error[E0434]: can't capture dynamic environment in a fn item
- --> $DIR/issue-3021.rs:12:22
- |
-LL | self.v0 = k0 ^ 0x736f6d6570736575;
- | ^^
- |
- = help: use the `|| { ... }` closure form instead
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0434`.
+++ /dev/null
-// Regression test for #30225, which was an ICE that would trigger as
-// a result of a poor interaction between trait result caching and
-// type inference. Specifically, at that time, unification could cause
-// unrelated type variables to become instantiated, if subtyping
-// relationships existed. These relationships are now propagated
-// through obligations and hence everything works out fine.
-
-trait Foo<U,V> : Sized {
- fn foo(self, u: Option<U>, v: Option<V>) {}
-}
-
-struct A;
-struct B;
-
-impl Foo<A, B> for () {} // impl A
-impl Foo<u32, u32> for u32 {} // impl B, creating ambiguity
-
-fn toxic() {
- // cache the resolution <() as Foo<$0,$1>> = impl A
- let u = None;
- let v = None;
- Foo::foo((), u, v);
-}
-
-fn bomb() {
- let mut u = None; // type is Option<$0>
- let mut v = None; // type is Option<$1>
- let mut x = None; // type is Option<$2>
-
- Foo::foo(x.unwrap(),u,v); // register <$2 as Foo<$0, $1>>
- u = v; // mark $0 and $1 in a subtype relationship
- //~^ ERROR mismatched types
- x = Some(()); // set $2 = (), allowing impl selection
- // to proceed for <() as Foo<$0, $1>> = impl A.
- // kaboom, this *used* to trigge an ICE
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-30225.rs:31:9
- |
-LL | u = v; // mark $0 and $1 in a subtype relationship
- | ^ expected struct `A`, found struct `B`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-pub struct X([u8]);
-
-pub static Y: &'static X = {
- const Y: &'static [u8] = b"";
- &X(*Y)
- //~^ ERROR E0277
-};
-
-fn main() {}
+++ /dev/null
-error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
- --> $DIR/issue-30355.rs:5:8
- |
-LL | &X(*Y)
- | ^^ doesn't have a size known at compile-time
- |
- = help: the trait `Sized` is not implemented for `[u8]`
- = note: all function arguments must have a statically known size
- = help: unsized fn params are gated as an unstable feature
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-#![feature(no_core, lang_items)]
-#![no_core]
-
-#[lang="sized"]
-trait Sized {}
-
-#[lang="add"]
-trait Add<T> {}
-
-impl Add<i32> for i32 {}
-
-fn main() {
- let x = 5 + 6;
- //~^ ERROR cannot add `i32` to `{integer}`
- let y = 5i32 + 6i32;
- //~^ ERROR cannot add `i32` to `i32`
-}
+++ /dev/null
-error[E0369]: cannot add `i32` to `{integer}`
- --> $DIR/issue-31076.rs:13:15
- |
-LL | let x = 5 + 6;
- | - ^ - i32
- | |
- | {integer}
-
-error[E0369]: cannot add `i32` to `i32`
- --> $DIR/issue-31076.rs:15:18
- |
-LL | let y = 5i32 + 6i32;
- | ---- ^ ---- i32
- | |
- | i32
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0369`.
struct M(PtrBack<Vec<M>>);
+#[allow(unused_must_use)]
fn main() {
std::mem::size_of::<M>();
}
+++ /dev/null
-// Test that error recovery in the parser to an EOF does not give an infinite
-// spew of errors.
-
-fn main() {
- let
-} //~ ERROR expected pattern, found `}`
+++ /dev/null
-error: expected pattern, found `}`
- --> $DIR/issue-31804.rs:6:1
- |
-LL | }
- | ^ expected pattern
-
-error: aborting due to previous error
-
+++ /dev/null
-// Checks lexical scopes cannot see through normal module boundaries
-
-fn f() {
- fn g() {}
- mod foo {
- fn h() {
- g(); //~ ERROR cannot find function `g` in this scope
- }
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0425]: cannot find function `g` in this scope
- --> $DIR/issue-31845.rs:7:12
- |
-LL | g();
- | ^ not found in this scope
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0425`.
+++ /dev/null
-// run-pass
-pub fn main() {
- let mut x = 0;
- for _ in 0..4096 { x += 1; }
- assert_eq!(x, 4096);
- println!("x = {}", x);
-}
+++ /dev/null
-extern "C" {
- fn foo(a: i32, ...);
-}
-
-fn bar(_: *const u8) {}
-
-fn main() {
- unsafe {
- foo(0, bar);
- //~^ ERROR can't pass `fn(*const u8) {bar}` to variadic function
- //~| HELP cast the value to `fn(*const u8)`
- }
-}
+++ /dev/null
-error[E0617]: can't pass `fn(*const u8) {bar}` to variadic function
- --> $DIR/issue-32201.rs:9:16
- |
-LL | foo(0, bar);
- | ^^^ help: cast the value to `fn(*const u8)`: `bar as fn(*const u8)`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0617`.
+++ /dev/null
-// run-pass
-
-fn quux<T>(x: T) -> T { let f = id::<T>; return f(x); }
-
-fn id<T>(x: T) -> T { return x; }
-
-pub fn main() { assert_eq!(quux(10), 10); }
+++ /dev/null
-// check-pass
-
-macro_rules! m {
- () => { #[cfg(any())] fn f() {} }
-}
-
-trait T {}
-impl T for () { m!(); }
-
-fn main() {}
+++ /dev/null
-// check-pass
-
-macro_rules! null { ($i:tt) => {} }
-macro_rules! apply_null {
- ($i:item) => { null! { $i } }
-}
-
-fn main() {
- apply_null!(#[cfg(all())] fn f() {});
-}
+++ /dev/null
-enum Test {
- Drill {
- field: i32,
- }
-}
-
-fn main() {
- Test::Drill(field: 42);
- //~^ ERROR invalid `struct` delimiters or `fn` call arguments
-}
+++ /dev/null
-error: invalid `struct` delimiters or `fn` call arguments
- --> $DIR/issue-34255-1.rs:8:5
- |
-LL | Test::Drill(field: 42);
- | ^^^^^^^^^^^^^^^^^^^^^^
- |
-help: if `Test::Drill` is a struct, use braces as delimiters
- |
-LL | Test::Drill { field: 42 };
- | ~ ~
-help: if `Test::Drill` is a function, use the arguments directly
- |
-LL - Test::Drill(field: 42);
-LL + Test::Drill(42);
- |
-
-error: aborting due to previous error
-
+++ /dev/null
-// build-pass
-#![allow(dead_code)]
-// Regression test for #35546. Check that we are able to codegen
-// this. Before we had problems because of the drop glue signature
-// around dropping a trait object (specifically, when dropping the
-// `value` field of `Node<Send>`).
-
-struct Node<T: ?Sized + Send> {
- next: Option<Box<Node<dyn Send>>>,
- value: T,
-}
-
-fn clear(head: &mut Option<Box<Node<dyn Send>>>) {
- match head.take() {
- Some(node) => *head = node.next,
- None => (),
- }
-}
-
-fn main() {}
+++ /dev/null
-// run-pass
-macro_rules! m { (<$t:ty>) => { stringify!($t) } }
-fn main() {
- println!("{}", m!(<Vec<i32>>));
-}
+++ /dev/null
-// check-pass
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-macro_rules! interrupt_handler {
- () => {
- unsafe fn _interrupt_handler() {
- llvm_asm!("pop eax" :::: "intel");
- }
- }
-}
-interrupt_handler!{}
-
-fn main() {}
+++ /dev/null
-const fn x() {
- let t = true;
- let x = || t; //~ ERROR function pointer
-}
-
-fn main() {}
+++ /dev/null
-error[E0658]: function pointers cannot appear in constant functions
- --> $DIR/issue-37550.rs:3:9
- |
-LL | let x = || t;
- | ^
- |
- = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
- = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
+++ /dev/null
-// run-pass
-
-const fn foo() -> i64 {
- 3
-}
-
-const fn bar(x: i64) -> i64 {
- x*2
-}
-
-fn main() {
- let val = &(foo() % 2);
- assert_eq!(*val, 1);
-
- let val2 = &(bar(1+1) % 3);
- assert_eq!(*val2, 1);
-}
+++ /dev/null
-trait Q<T:?Sized> {}
-trait Foo where u32: Q<Self> {
- fn foo(&self);
-}
-
-impl Q<()> for u32 {}
-impl Foo for () {
- fn foo(&self) {
- println!("foo!");
- }
-}
-
-fn main() {
- let _f: Box<dyn Foo> = //~ ERROR `Foo` cannot be made into an object
- Box::new(()); //~ ERROR `Foo` cannot be made into an object
-}
+++ /dev/null
-error[E0038]: the trait `Foo` cannot be made into an object
- --> $DIR/issue-38604.rs:14:13
- |
-LL | let _f: Box<dyn Foo> =
- | ^^^^^^^^^^^^ `Foo` cannot be made into an object
- |
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
- --> $DIR/issue-38604.rs:2:22
- |
-LL | trait Foo where u32: Q<Self> {
- | --- ^^^^^^^ ...because it uses `Self` as a type parameter
- | |
- | this trait cannot be made into an object...
-
-error[E0038]: the trait `Foo` cannot be made into an object
- --> $DIR/issue-38604.rs:15:9
- |
-LL | Box::new(());
- | ^^^^^^^^^^^^ `Foo` cannot be made into an object
- |
-note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
- --> $DIR/issue-38604.rs:2:22
- |
-LL | trait Foo where u32: Q<Self> {
- | --- ^^^^^^^ ...because it uses `Self` as a type parameter
- | |
- | this trait cannot be made into an object...
- = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn Foo>>` for `Box<()>`
- = note: required by cast to type `Box<dyn Foo>`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0038`.
+++ /dev/null
-#![allow(unused_macros)]
-
-macro_rules! assign {
- (($($a:tt)*) = ($($b:tt))*) => { //~ ERROR expected one of: `*`, `+`, or `?`
- $($a)* = $($b)*
- }
-}
-
-fn main() {}
+++ /dev/null
-error: expected one of: `*`, `+`, or `?`
- --> $DIR/issue-39388.rs:4:22
- |
-LL | (($($a:tt)*) = ($($b:tt))*) => {
- | ^^^^^^^
-
-error: aborting due to previous error
-
+++ /dev/null
-struct Point {
- x: f64,
- y: f64,
-}
-
-trait ToString_ {
- fn to_string(&self) -> String;
-}
-
-impl ToString_ for Point {
- fn new(x: f64, y: f64) -> Point {
- //~^ ERROR method `new` is not a member of trait `ToString_`
- Point { x: x, y: y }
- }
-
- fn to_string(&self) -> String {
- format!("({}, {})", self.x, self.y)
- }
-}
-
-fn main() {
- let p = Point::new(0.0, 0.0);
- //~^ ERROR no function or associated item named `new` found for struct `Point`
- println!("{}", p.to_string());
-}
+++ /dev/null
-error[E0407]: method `new` is not a member of trait `ToString_`
- --> $DIR/issue-3973.rs:11:5
- |
-LL | / fn new(x: f64, y: f64) -> Point {
-LL | |
-LL | | Point { x: x, y: y }
-LL | | }
- | |_____^ not a member of trait `ToString_`
-
-error[E0599]: no function or associated item named `new` found for struct `Point` in the current scope
- --> $DIR/issue-3973.rs:22:20
- |
-LL | struct Point {
- | ------------ function or associated item `new` not found for this
-...
-LL | let p = Point::new(0.0, 0.0);
- | ^^^ function or associated item not found in `Point`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0407, E0599.
-For more information about an error, try `rustc --explain E0407`.
+++ /dev/null
-// run-pass
-// aux-build:issue-39823.rs
-
-extern crate issue_39823;
-use issue_39823::{RemoteC, RemoteG};
-
-#[derive(Debug, PartialEq)]
-struct LocalC(u32);
-
-#[derive(Debug, PartialEq)]
-struct LocalG<T>(T);
-
-fn main() {
- let virtual_localc : &dyn Fn(_) -> LocalC = &LocalC;
- assert_eq!(virtual_localc(1), LocalC(1));
-
- let virtual_localg : &dyn Fn(_) -> LocalG<u32> = &LocalG;
- assert_eq!(virtual_localg(1), LocalG(1));
-
- let virtual_remotec : &dyn Fn(_) -> RemoteC = &RemoteC;
- assert_eq!(virtual_remotec(1), RemoteC(1));
-
- let virtual_remoteg : &dyn Fn(_) -> RemoteG<u32> = &RemoteG;
- assert_eq!(virtual_remoteg(1), RemoteG(1));
-}
+++ /dev/null
-// run-pass
-#![allow(unused_macros)]
-macro_rules! m {
- ($e:expr) => {
- macro_rules! n { () => { $e } }
- }
-}
-
-fn main() {
- m!(foo!());
-}
error[E0277]: `Rc<Foo>` cannot be shared between threads safely
- --> $DIR/issue-40827.rs:14:5
+ --> $DIR/issue-40827.rs:14:7
|
LL | f(Foo(Arc::new(Bar::B(None))));
- | ^ `Rc<Foo>` cannot be shared between threads safely
+ | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rc<Foo>` cannot be shared between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `Bar`, the trait `Sync` is not implemented for `Rc<Foo>`
note: required because it appears within the type `Bar`
| ^^^^ required by this bound in `f`
error[E0277]: `Rc<Foo>` cannot be sent between threads safely
- --> $DIR/issue-40827.rs:14:5
+ --> $DIR/issue-40827.rs:14:7
|
LL | f(Foo(Arc::new(Bar::B(None))));
- | ^ `Rc<Foo>` cannot be sent between threads safely
+ | - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rc<Foo>` cannot be sent between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `Bar`, the trait `Send` is not implemented for `Rc<Foo>`
note: required because it appears within the type `Bar`
+++ /dev/null
-// check-pass
-macro_rules! m {
- ($i:meta) => {
- #[derive($i)]
- struct S;
- }
-}
-
-m!(Clone);
-
-fn main() {}
+++ /dev/null
-// run-pass
-use std::ops::{Deref, DerefMut};
-
-struct CheckedDeref<T, F> {
- value: T,
- check: F
-}
-
-impl<F: Fn(&T) -> bool, T> Deref for CheckedDeref<T, F> {
- type Target = T;
- fn deref(&self) -> &T {
- assert!((self.check)(&self.value));
- &self.value
- }
-}
-
-impl<F: Fn(&T) -> bool, T> DerefMut for CheckedDeref<T, F> {
- fn deref_mut(&mut self) -> &mut T {
- assert!((self.check)(&self.value));
- &mut self.value
- }
-}
-
-
-fn main() {
- let mut v = CheckedDeref {
- value: vec![0],
- check: |v: &Vec<_>| !v.is_empty()
- };
- v.push(1);
- assert_eq!(*v, vec![0, 1]);
-}
+++ /dev/null
-// run-pass
-#![feature(box_syntax)]
-#![feature(box_patterns)]
-
-#[derive(Debug, PartialEq)]
-enum Test {
- Foo(usize),
- Bar(isize),
-}
-
-fn main() {
- let a = box Test::Foo(10);
- let b = box Test::Bar(-20);
- match (a, b) {
- (_, box Test::Foo(_)) => unreachable!(),
- (box Test::Foo(x), b) => {
- assert_eq!(x, 10);
- assert_eq!(b, box Test::Bar(-20));
- },
- _ => unreachable!(),
- }
-}
+++ /dev/null
-// run-pass
-macro_rules! fooN {
- ($cur:ident $prev:ty) => {
- #[allow(dead_code)]
- enum $cur {
- Empty,
- First($prev),
- Second($prev),
- Third($prev),
- Fourth($prev),
- }
- }
-}
-
-fooN!(Foo0 ());
-fooN!(Foo1 Foo0);
-fooN!(Foo2 Foo1);
-fooN!(Foo3 Foo2);
-fooN!(Foo4 Foo3);
-fooN!(Foo5 Foo4);
-fooN!(Foo6 Foo5);
-fooN!(Foo7 Foo6);
-fooN!(Foo8 Foo7);
-fooN!(Foo9 Foo8);
-fooN!(Foo10 Foo9);
-fooN!(Foo11 Foo10);
-fooN!(Foo12 Foo11);
-fooN!(Foo13 Foo12);
-fooN!(Foo14 Foo13);
-fooN!(Foo15 Foo14);
-fooN!(Foo16 Foo15);
-fooN!(Foo17 Foo16);
-fooN!(Foo18 Foo17);
-fooN!(Foo19 Foo18);
-fooN!(Foo20 Foo19);
-fooN!(Foo21 Foo20);
-fooN!(Foo22 Foo21);
-fooN!(Foo23 Foo22);
-fooN!(Foo24 Foo23);
-fooN!(Foo25 Foo24);
-fooN!(Foo26 Foo25);
-fooN!(Foo27 Foo26);
-
-fn main() {
- let _foo = Foo27::Empty;
-}
+++ /dev/null
-// Issue 46112: An extern crate pub re-exporting libcore was causing
-// paths rooted from `std` to be misrendered in the diagnostic output.
-
-// ignore-windows
-// aux-build:xcrate-issue-43189-a.rs
-// aux-build:xcrate-issue-43189-b.rs
-
-extern crate xcrate_issue_43189_b;
-fn main() {
- ().a();
- //~^ ERROR no method named `a` found
-}
+++ /dev/null
-error[E0599]: no method named `a` found for unit type `()` in the current scope
- --> $DIR/issue-43189.rs:10:8
- |
-LL | ().a();
- | ^ method not found in `()`
- |
- ::: $DIR/auxiliary/xcrate-issue-43189-a.rs:5:8
- |
-LL | fn a(&self) {}
- | - the method is available for `()` here
- |
- = help: items from traits can only be used if the trait is in scope
-help: the following trait is implemented but not in scope; perhaps add a `use` for it:
- |
-LL | use xcrate_issue_43189_b::xcrate_issue_43189_a::A;
- |
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0599`.
+++ /dev/null
-pub trait Foo<'a> {
- type Bar;
- fn foo(&'a self) -> Self::Bar;
-}
-
-impl<'a, 'b, T: 'a> Foo<'a> for &'b T {
- type Bar = &'a T;
- fn foo(&'a self) -> &'a T {
- self
- }
-}
-
-pub fn uncallable<T, F>(x: T, f: F)
-where
- T: for<'a> Foo<'a>,
- F: for<'a> Fn(<T as Foo<'a>>::Bar),
-{
- f(x.foo());
-}
-
-pub fn catalyst(x: &i32) {
- broken(x, |_| {})
-}
-
-pub fn broken<F: Fn(&i32)>(x: &i32, f: F) {
- uncallable(x, |y| f(y));
- //~^ type mismatch
-}
-
-fn main() {}
+++ /dev/null
-error[E0631]: type mismatch in closure arguments
- --> $DIR/issue-44005.rs:26:5
- |
-LL | uncallable(x, |y| f(y));
- | ^^^^^^^^^^ -------- found signature of `for<'r> fn(&'r i32) -> _`
- | |
- | expected signature of `for<'a> fn(<&i32 as Foo<'a>>::Bar) -> _`
- |
-note: required by a bound in `uncallable`
- --> $DIR/issue-44005.rs:16:8
- |
-LL | pub fn uncallable<T, F>(x: T, f: F)
- | ---------- required by a bound in this
-...
-LL | F: for<'a> Fn(<T as Foo<'a>>::Bar),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `uncallable`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0631`.
+++ /dev/null
-// run-pass
-pub fn main() {
- let mut count = 0;
- for _ in 0..999_999 { count += 1; }
- assert_eq!(count, 999_999);
- println!("{}", count);
-}
+++ /dev/null
-// run-pass
-// ignore-emscripten no threads support
-
-use std::sync::mpsc::channel;
-use std::thread;
-
-pub fn main() {
- let (tx, rx) = channel::<&'static str>();
-
- let t = thread::spawn(move|| {
- assert_eq!(rx.recv().unwrap(), "hello, world");
- });
-
- tx.send("hello, world").unwrap();
- t.join().ok().unwrap();
-}
+++ /dev/null
-// run-pass
-#![allow(unreachable_code)]
-// compile-flags: --edition 2018
-
-#![feature(try_blocks)]
-
-fn main() {
- let mut a = 0;
- let () = {
- let _: Result<(), ()> = try {
- let _ = Err(())?;
- return
- };
- a += 1;
- };
- a += 2;
- assert_eq!(a, 3);
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-#![allow(unused_variables)]
-#![feature(unsize, coerce_unsized)]
-
-#[repr(packed)]
-struct UnalignedPtr<'a, T: ?Sized>
- where T: 'a,
-{
- data: &'a T,
-}
-
-fn main() {
-
- impl<'a, T, U> std::ops::CoerceUnsized<UnalignedPtr<'a, U>> for UnalignedPtr<'a, T>
- where
- T: std::marker::Unsize<U> + ?Sized,
- U: ?Sized,
- { }
-
- let arr = [1, 2, 3];
- let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr };
- let arr_unaligned: UnalignedPtr<[i32]> = arr_unaligned;
-}
+++ /dev/null
-// run-pass
-struct A;
-
-impl A {
- fn take_mutably(&mut self) {}
-}
-
-fn identity<T>(t: T) -> T {
- t
-}
-
-// Issue 46095
-// Built-in indexing should be used even when the index is not
-// trivially an integer
-// Overloaded indexing would cause wrapped to be borrowed mutably
-
-fn main() {
- let mut a1 = A;
- let mut a2 = A;
-
- let wrapped = [&mut a1, &mut a2];
-
- {
- wrapped[0 + 1 - 1].take_mutably();
- }
-
- {
- wrapped[identity(0)].take_mutably();
- }
-}
+++ /dev/null
-// Issue 46112: An extern crate pub re-exporting libcore was causing
-// paths rooted from `std` to be misrendered in the diagnostic output.
-
-// ignore-windows
-// aux-build:xcrate-issue-46112-rexport-core.rs
-
-extern crate xcrate_issue_46112_rexport_core;
-fn test(r: Result<Option<()>, &'static str>) { }
-fn main() { test(Ok(())); }
-//~^ mismatched types
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-46112.rs:9:21
- |
-LL | fn main() { test(Ok(())); }
- | ^^
- | |
- | expected enum `Option`, found `()`
- | help: try using a variant of the expected enum: `Some(())`
- |
- = note: expected enum `Option<()>`
- found unit type `()`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// run-pass
-// Regression test for issue #47139:
-//
-// Coherence was encountering an (unnecessary) overflow trying to
-// decide if the two impls of dummy overlap.
-//
-// The overflow went something like:
-//
-// - `&'a ?T: Insertable` ?
-// - let ?T = Option<?U> ?
-// - `Option<?U>: Insertable` ?
-// - `Option<&'a ?U>: Insertable` ?
-// - `&'a ?U: Insertable` ?
-//
-// While somewhere in the middle, a projection would occur, which
-// broke cycle detection.
-//
-// It turned out that this cycle was being kicked off due to some
-// extended diagnostic attempts in coherence, so removing those
-// sidestepped the issue for now.
-
-#![allow(dead_code)]
-
-pub trait Insertable {
- type Values;
-
- fn values(self) -> Self::Values;
-}
-
-impl<T> Insertable for Option<T>
- where
- T: Insertable,
- T::Values: Default,
-{
- type Values = T::Values;
-
- fn values(self) -> Self::Values {
- self.map(Insertable::values).unwrap_or_default()
- }
-}
-
-impl<'a, T> Insertable for &'a Option<T>
- where
- Option<&'a T>: Insertable,
-{
- type Values = <Option<&'a T> as Insertable>::Values;
-
- fn values(self) -> Self::Values {
- self.as_ref().values()
- }
-}
-
-impl<'a, T> Insertable for &'a [T]
-{
- type Values = Self;
-
- fn values(self) -> Self::Values {
- self
- }
-}
-
-trait Unimplemented { }
-
-trait Dummy { }
-
-struct Foo<T> { t: T }
-
-impl<'a, U> Dummy for Foo<&'a U>
- where &'a U: Insertable
-{
-}
-
-impl<T> Dummy for T
- where T: Unimplemented
-{ }
-
-fn main() {
-}
+++ /dev/null
-#![allow(unused_variables)]; //~ ERROR expected item, found `;`
-//~^ ERROR `main` function
-fn foo() {}
+++ /dev/null
-error: expected item, found `;`
- --> $DIR/issue-49040.rs:1:28
- |
-LL | #![allow(unused_variables)];
- | ^ help: remove this semicolon
-
-error[E0601]: `main` function not found in crate `issue_49040`
- --> $DIR/issue-49040.rs:1:1
- |
-LL | #![allow(unused_variables)];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/issue-49040.rs`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0601`.
+++ /dev/null
-// check-pass
-
-fn fibs(n: u32) -> impl Iterator<Item=u128> {
- (0 .. n)
- .scan((0, 1), |st, _| {
- *st = (st.1, st.0 + st.1);
- Some(*st)
- })
- .map(&|(f, _)| f)
-}
-
-fn main() {
- println!("{:?}", fibs(10).collect::<Vec<_>>());
-}
+++ /dev/null
-// run-pass
-// Regression test for #49685: drop elaboration was not revealing the
-// value of `impl Trait` returns, leading to an ICE.
-
-fn main() {
- let _ = Some(())
- .into_iter()
- .flat_map(|_| Some(()).into_iter().flat_map(func));
-}
-
-fn func(_: ()) -> impl Iterator<Item = ()> {
- Some(()).into_iter().flat_map(|_| vec![])
-}
+++ /dev/null
-// run-pass
-enum Void {}
-fn foo(_: Result<(Void, u32), (Void, String)>) {}
-fn main() {
- let _: fn(_) = foo;
-}
+++ /dev/null
-trait B <A> {
- fn a() -> A {
- this.a //~ ERROR cannot find value `this` in this scope
- }
- fn b(x: i32) {
- this.b(x); //~ ERROR cannot find value `this` in this scope
- }
- fn c() {
- let _ = || this.a; //~ ERROR cannot find value `this` in this scope
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0425]: cannot find value `this` in this scope
- --> $DIR/issue-5099.rs:3:9
- |
-LL | this.a
- | ^^^^ not found in this scope
- |
-help: you might have meant to use `self` here instead
- |
-LL | self.a
- | ~~~~
-help: if you meant to use `self`, you are also missing a `self` receiver argument
- |
-LL | fn a(&self) -> A {
- | +++++
-
-error[E0425]: cannot find value `this` in this scope
- --> $DIR/issue-5099.rs:6:9
- |
-LL | this.b(x);
- | ^^^^ not found in this scope
- |
-help: you might have meant to use `self` here instead
- |
-LL | self.b(x);
- | ~~~~
-help: if you meant to use `self`, you are also missing a `self` receiver argument
- |
-LL | fn b(&self, x: i32) {
- | ++++++
-
-error[E0425]: cannot find value `this` in this scope
- --> $DIR/issue-5099.rs:9:20
- |
-LL | let _ = || this.a;
- | ^^^^ not found in this scope
- |
-help: you might have meant to use `self` here instead
- |
-LL | let _ = || self.a;
- | ~~~~
-help: if you meant to use `self`, you are also missing a `self` receiver argument
- |
-LL | fn c(&self) {
- | +++++
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0425`.
+++ /dev/null
-// compile-flags: --crate-type dylib --target thumbv7em-none-eabihf
-// needs-llvm-components: arm
-// build-pass
-// error-pattern: dropping unsupported crate type `dylib` for target `thumbv7em-none-eabihf`
-
-#![feature(no_core)]
-
-#![no_std]
-#![no_core]
+++ /dev/null
-warning: dropping unsupported crate type `dylib` for target `thumbv7em-none-eabihf`
-
-warning: 1 warning emitted
-
+++ /dev/null
-// run-pass
-fn foo() -> impl Into<for<'a> fn(&'a ())> {
- (|_| {}) as for<'a> fn(&'a ())
-}
-
-fn main() {
- foo().into()(&());
-}
+++ /dev/null
-// run-pass
-#![allow(unreachable_code)]
-
-fn main() {
- let mut v = Vec::new();
-
- loop { v.push(break) }
-}
+++ /dev/null
-// run-pass
-#![feature(core_intrinsics)]
-
-#[repr(i8)]
-pub enum Enum {
- VariantA,
- VariantB,
-}
-
-fn make_b() -> Enum { Enum::VariantB }
-
-fn main() {
- assert_eq!(1, make_b() as i8);
- assert_eq!(1, make_b() as u8);
- assert_eq!(1, make_b() as i32);
- assert_eq!(1, make_b() as u32);
- assert_eq!(1, std::intrinsics::discriminant_value(&make_b()));
-}
+++ /dev/null
-// Regression test for Issue #53787: Fix ICE when creating a label in inline assembler with macros.
-
-// build-fail
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-macro_rules! fake_jump {
- ($id:expr) => {
- unsafe {
- llvm_asm!(
- "
- jmp $0
- lea eax, [ebx]
- xor eax, 0xDEADBEEF
- retn
- $0:
- "::"0"($id)::"volatile", "intel");
- }
- };
-}
-
-fn main() {
- fake_jump!("FirstFunc"); //~ ERROR invalid value for constraint in inline assembly
- println!("Hello, world!");
-}
+++ /dev/null
-error[E0669]: invalid value for constraint in inline assembly
- --> $DIR/issue-53787-inline-assembler-macro.rs:25:16
- |
-LL | fake_jump!("FirstFunc");
- | ^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0669`.
+++ /dev/null
-// run-pass
-
-pub trait Stream {
- type Item;
- type Error;
-}
-
-pub trait ParseError<I> {
- type Output;
-}
-
-impl ParseError<char> for u32 {
- type Output = ();
-}
-
-impl Stream for () {
- type Item = char;
- type Error = u32;
-}
-
-pub struct Lex<'a, I>
- where I: Stream,
- I::Error: ParseError<char>,
- <<I as Stream>::Error as ParseError<char>>::Output: 'a
-{
- x: &'a <I::Error as ParseError<char>>::Output
-}
-
-pub struct Reserved<'a, I> where
- I: Stream<Item=char> + 'a,
- I::Error: ParseError<I::Item>,
- <<I as Stream>::Error as ParseError<char>>::Output: 'a
-
-{
- x: Lex<'a, I>
-}
-
-fn main() {
- let r: Reserved<()> = Reserved {
- x: Lex {
- x: &()
- }
- };
-
- let _v = r.x.x;
-}
+++ /dev/null
-struct T;
-
-impl for T {}
-//~^ ERROR missing trait in a trait impl
-
-fn main() {}
+++ /dev/null
-error: missing trait in a trait impl
- --> $DIR/issue-56031.rs:3:5
- |
-LL | impl for T {}
- | ^
- |
-help: add a trait here
- |
-LL | impl Trait for T {}
- | +++++
-help: for an inherent impl, drop this `for`
- |
-LL - impl for T {}
-LL + impl T {}
- |
-
-error: aborting due to previous error
-
+++ /dev/null
-// check-pass
-
-// Originally from #53925.
-// Tests that the `unreachable_pub` lint doesn't fire for `pub self::bar::Bar`.
-
-#![deny(unreachable_pub)]
-
-mod foo {
- mod bar {
- pub struct Bar;
- }
-
- pub use self::bar::Bar;
-}
-
-pub use foo::Bar;
-
-fn main() {}
+++ /dev/null
-// Regression test for #57597.
-//
-// Make sure that nested matchers work correctly rather than causing an infinite loop or crash.
-
-// edition:2018
-
-macro_rules! foo1 {
- ($($($i:ident)?)+) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo2 {
- ($($($i:ident)?)*) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo3 {
- ($($($i:ident)?)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo4 {
- ($($($($i:ident)?)?)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo5 {
- ($($($($i:ident)*)?)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo6 {
- ($($($($i:ident)?)*)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo7 {
- ($($($($i:ident)?)?)*) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo8 {
- ($($($($i:ident)*)*)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo9 {
- ($($($($i:ident)?)*)*) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo10 {
- ($($($($i:ident)?)*)+) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo11 {
- ($($($($i:ident)+)?)*) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-macro_rules! foo12 {
- ($($($($i:ident)+)*)?) => {};
- //~^ ERROR repetition matches empty token tree
-}
-
-fn main() {
- foo1!();
- foo2!();
- foo3!();
- foo4!();
- foo5!();
- foo6!();
- foo7!();
- foo8!();
- foo9!();
- foo10!();
- foo11!();
- foo12!();
-}
+++ /dev/null
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:8:7
- |
-LL | ($($($i:ident)?)+) => {};
- | ^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:13:7
- |
-LL | ($($($i:ident)?)*) => {};
- | ^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:18:7
- |
-LL | ($($($i:ident)?)?) => {};
- | ^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:23:7
- |
-LL | ($($($($i:ident)?)?)?) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:28:7
- |
-LL | ($($($($i:ident)*)?)?) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:33:7
- |
-LL | ($($($($i:ident)?)*)?) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:38:7
- |
-LL | ($($($($i:ident)?)?)*) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:43:7
- |
-LL | ($($($($i:ident)*)*)?) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:48:7
- |
-LL | ($($($($i:ident)?)*)*) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:53:7
- |
-LL | ($($($($i:ident)?)*)+) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:58:7
- |
-LL | ($($($($i:ident)+)?)*) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: repetition matches empty token tree
- --> $DIR/issue-57597.rs:63:7
- |
-LL | ($($($($i:ident)+)*)?) => {};
- | ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 12 previous errors
-
+++ /dev/null
-// run-pass
-fn main() {}
-#[derive(Clone)]
-pub struct Little;
-#[derive(Clone)]
-pub struct Big(
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
- Little,
-);
+++ /dev/null
-#![feature(trait_alias)]
-
-trait Svc<Req> { type Res; }
-
-trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
-//~^ ERROR associated type `Res` not found for `Self`
-//~| ERROR associated type `Res` not found for `Self`
-
-fn main() {}
+++ /dev/null
-error[E0220]: associated type `Res` not found for `Self`
- --> $DIR/issue-59029-1.rs:5:52
- |
-LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
- | ^^^ associated type `Res` not found
-
-error[E0220]: associated type `Res` not found for `Self`
- --> $DIR/issue-59029-1.rs:5:52
- |
-LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
- | ^^^ associated type `Res` not found
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0220`.
+++ /dev/null
-#![allow(dead_code)]
-#![feature(const_generics_defaults)]
-
-// This test checks that generic parameter re-ordering diagnostic suggestions mention that
-// consts come after types and lifetimes when the `const_generics_defaults` feature is enabled.
-// We cannot run rustfix on this test because of the above const generics warning.
-
-struct A;
-
-impl A {
- pub fn do_things<T, 'a, 'b: 'a>() {
- //~^ ERROR lifetime parameters must be declared prior to type parameters
- println!("panic");
- }
-}
-
-fn main() {}
+++ /dev/null
-error: lifetime parameters must be declared prior to type parameters
- --> $DIR/issue-59508-1.rs:11:25
- |
-LL | pub fn do_things<T, 'a, 'b: 'a>() {
- | ----^^--^^----- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b: 'a, T>`
-
-error: aborting due to previous error
-
+++ /dev/null
-// run-rustfix
-
-#![allow(dead_code)]
-
-// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
-
-struct A;
-
-impl A {
- pub fn do_things<'a, 'b: 'a, T>() {
- //~^ ERROR lifetime parameters must be declared prior to type parameters
- println!("panic");
- }
-}
-
-fn main() {}
+++ /dev/null
-// run-rustfix
-
-#![allow(dead_code)]
-
-// This test checks that generic parameter re-ordering diagnostic suggestions contain bounds.
-
-struct A;
-
-impl A {
- pub fn do_things<T, 'a, 'b: 'a>() {
- //~^ ERROR lifetime parameters must be declared prior to type parameters
- println!("panic");
- }
-}
-
-fn main() {}
+++ /dev/null
-error: lifetime parameters must be declared prior to type parameters
- --> $DIR/issue-59508.rs:10:25
- |
-LL | pub fn do_things<T, 'a, 'b: 'a>() {
- | ----^^--^^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b: 'a, T>`
-
-error: aborting due to previous error
-
+++ /dev/null
-pub trait Trait<'a> {
- type Item;
-}
-
-impl<'a> Trait<'a> for () {
- type Item = ();
-}
-
-pub fn foo<T, F>(_: T, _: F)
-where
- T: for<'a> Trait<'a>,
- F: for<'a> FnMut(<T as Trait<'a>>::Item),
-{
-}
-
-fn main() {
- foo((), drop)
- //~^ ERROR type mismatch in function arguments
- //~| ERROR size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
-}
+++ /dev/null
-error[E0631]: type mismatch in function arguments
- --> $DIR/issue-60283.rs:17:13
- |
-LL | foo((), drop)
- | --- ^^^^
- | | |
- | | expected signature of `for<'a> fn(<() as Trait<'a>>::Item) -> _`
- | | found signature of `fn(()) -> _`
- | required by a bound introduced by this call
- |
-note: required by a bound in `foo`
- --> $DIR/issue-60283.rs:12:16
- |
-LL | pub fn foo<T, F>(_: T, _: F)
- | --- required by a bound in this
-...
-LL | F: for<'a> FnMut(<T as Trait<'a>>::Item),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
-
-error[E0277]: the size for values of type `<() as Trait<'_>>::Item` cannot be known at compilation time
- --> $DIR/issue-60283.rs:17:13
- |
-LL | foo((), drop)
- | --- ^^^^ doesn't have a size known at compile-time
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Sized` is not implemented for `<() as Trait<'_>>::Item`
-note: required by a bound in `std::mem::drop`
- --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
- |
-LL | pub fn drop<T>(_x: T) {}
- | ^ required by this bound in `std::mem::drop`
-help: consider further restricting the associated type
- |
-LL | fn main() where <() as Trait<'_>>::Item: Sized {
- | ++++++++++++++++++++++++++++++++++++
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0277, E0631.
-For more information about an error, try `rustc --explain E0277`.
+++ /dev/null
-// check-pass
-// compile-flags: -Z unpretty=hir
-
-#![feature(type_alias_impl_trait)]
-
-trait Animal {}
-
-fn main() {
- pub type ServeFut = impl Animal;
-}
+++ /dev/null
-// check-pass
-// compile-flags: -Z unpretty=hir
-
-#![feature(type_alias_impl_trait)]
-#[prelude_import]
-use ::std::prelude::rust_2015::*;
-#[macro_use]
-extern crate std;
-
-trait Animal { }
-
-fn main() {
- pub type ServeFut = /*impl Trait*/;
- }
+++ /dev/null
-// Issue 61711: A crate pub re-exporting `crate` was causing an
-// infinite loop.
-
-// edition:2018
-// aux-build:xcrate-issue-61711-b.rs
-// compile-flags:--extern xcrate_issue_61711_b
-
-// build-pass
-
-fn f<F: Fn(xcrate_issue_61711_b::Struct)>(_: F) { }
-fn main() { }
+++ /dev/null
-struct A<T>(T);
-
-impl A<&'static u8> {
- fn f() {
- let x = 0;
- Self(&x);
- //~^ ERROR `x` does not live long enough
- }
-}
-
-fn main() {}
+++ /dev/null
-error[E0597]: `x` does not live long enough
- --> $DIR/issue-61882-2.rs:6:14
- |
-LL | Self(&x);
- | ^^
- | |
- | borrowed value does not live long enough
- | this usage requires that `x` is borrowed for `'static`
-LL |
-LL | }
- | - `x` dropped here while still borrowed
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0597`.
+++ /dev/null
-struct A<T>(T);
-
-impl A<bool> {
- const B: A<u8> = Self(0);
- //~^ ERROR mismatched types
- //~| ERROR mismatched types
-}
-
-fn main() {}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-61882.rs:4:27
- |
-LL | const B: A<u8> = Self(0);
- | ^ expected `bool`, found integer
-
-error[E0308]: mismatched types
- --> $DIR/issue-61882.rs:4:22
- |
-LL | const B: A<u8> = Self(0);
- | ^^^^^^^ expected `u8`, found `bool`
- |
- = note: expected struct `A<u8>`
- found struct `A<bool>`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-fn part(_: u16) -> u32 {
- 1
-}
-
-fn main() {
- for n in 100_000.. {
- //~^ ERROR: literal out of range for `u16`
- let _ = part(n);
- }
-}
+++ /dev/null
-error: literal out of range for `u16`
- --> $DIR/issue-63364.rs:6:14
- |
-LL | for n in 100_000.. {
- | ^^^^^^^
- |
- = note: `#[deny(overflowing_literals)]` on by default
- = note: the literal `100_000` does not fit into the type `u16` whose range is `0..=65535`
-
-error: aborting due to previous error
-
+++ /dev/null
-macro_rules! e {
- ($inp:ident) => (
- $nonexistent
- //~^ ERROR expected expression, found `$`
- );
-}
-
-fn main() {
- e!(foo);
-}
+++ /dev/null
-error: expected expression, found `$`
- --> $DIR/issue-6596-1.rs:3:9
- |
-LL | $nonexistent
- | ^^^^^^^^^^^^ expected expression
-...
-LL | e!(foo);
- | ------- in this macro invocation
- |
- = note: this error originates in the macro `e` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
+++ /dev/null
-// Matching against NaN should result in a warning
-
-#![allow(unused)]
-#![deny(illegal_floating_point_literal_pattern)]
-
-const NAN: f64 = f64::NAN;
-
-fn main() {
- let x = NAN;
- match x {
- NAN => {}, //~ ERROR floating-point types cannot be used
- //~| WARN this was previously accepted by the compiler but is being phased out
- _ => {},
- };
-
- match [x, 1.0] {
- [NAN, _] => {}, //~ ERROR floating-point types cannot be used
- //~| WARN this was previously accepted by the compiler but is being phased out
- _ => {},
- };
-}
+++ /dev/null
-error: floating-point types cannot be used in patterns
- --> $DIR/issue-6804.rs:11:9
- |
-LL | NAN => {},
- | ^^^
- |
-note: the lint level is defined here
- --> $DIR/issue-6804.rs:4:9
- |
-LL | #![deny(illegal_floating_point_literal_pattern)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = 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>
-
-error: floating-point types cannot be used in patterns
- --> $DIR/issue-6804.rs:17:10
- |
-LL | [NAN, _] => {},
- | ^^^
- |
- = 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>
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// check-pass
-
-pub trait ResultExt {
- type Ok;
- fn err_eprint_and_ignore(self) -> Option<Self::Ok>;
-}
-
-impl<O, E> ResultExt for std::result::Result<O, E>
-where
- E: std::error::Error,
-{
- type Ok = O;
- fn err_eprint_and_ignore(self) -> Option<O>
- where
- Self: ,
- {
- match self {
- Err(e) => {
- eprintln!("{}", e);
- None
- }
- Ok(o) => Some(o),
- }
- }
-}
-
-fn main() {}
pub unsafe fn g() {
return;
if *ptr::null() {}; //~ ERROR unreachable
+ //~| WARNING dereferencing a null pointer
}
pub fn main() {}
LL | #![deny(unreachable_code)]
| ^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+warning: dereferencing a null pointer
+ --> $DIR/issue-7246.rs:7:8
+ |
+LL | if *ptr::null() {};
+ | ^^^^^^^^^^^^ this code causes undefined behavior when executed
+ |
+ = note: `#[warn(deref_nullptr)]` on by default
+
+error: aborting due to previous error; 1 warning emitted
+++ /dev/null
-struct Binder(i32, i32, i32);
-
-fn main() {
- let x = Binder(1, 2, 3);
- match x {
- Binder(_a, _x @ ..) => {}
- _ => {}
- }
-}
-//~^^^^ ERROR `_x @` is not allowed in a tuple struct
-//~| ERROR: `..` patterns are not allowed here
-//~| ERROR: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
+++ /dev/null
-error: `_x @` is not allowed in a tuple struct
- --> $DIR/issue-72574-2.rs:6:20
- |
-LL | Binder(_a, _x @ ..) => {}
- | ^^^^^^^ this is only allowed in slice patterns
- |
- = help: remove this and bind each tuple field independently
-help: if you don't need to use the contents of _x, discard the tuple's remaining fields
- |
-LL | Binder(_a, ..) => {}
- | ~~
-
-error: `..` patterns are not allowed here
- --> $DIR/issue-72574-2.rs:6:25
- |
-LL | Binder(_a, _x @ ..) => {}
- | ^^
- |
- = note: only allowed in tuple, tuple struct, and slice patterns
-
-error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
- --> $DIR/issue-72574-2.rs:6:16
- |
-LL | struct Binder(i32, i32, i32);
- | --- --- --- tuple struct has 3 fields
-...
-LL | Binder(_a, _x @ ..) => {}
- | ^^ ^^^^^^^ expected 3 fields, found 2
- |
-help: use `_` to explicitly ignore each field
- |
-LL | Binder(_a, _x @ .., _) => {}
- | +++
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0023`.
+++ /dev/null
-// edition:2018
-
-fn main() {
- 'a: loop {
- async {
- loop {
- continue 'a
- //~^ ERROR use of unreachable label `'a`
- }
- };
- }
-}
+++ /dev/null
-error[E0767]: use of unreachable label `'a`
- --> $DIR/issue-73541-1.rs:7:26
- |
-LL | 'a: loop {
- | -- unreachable label defined here
-...
-LL | continue 'a
- | ^^ unreachable label `'a`
- |
- = note: labels are unreachable through functions, closures, async blocks and modules
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0767`.
+++ /dev/null
-fn main() {
- let _ = &&[0] as &[_];
- //~^ ERROR non-primitive cast: `&&[i32; 1]` as `&[_]`
- let _ = 7u32 as Option<_>;
- //~^ ERROR non-primitive cast: `u32` as `Option<_>`
-}
+++ /dev/null
-error[E0605]: non-primitive cast: `&&[i32; 1]` as `&[_]`
- --> $DIR/issue-73886.rs:2:13
- |
-LL | let _ = &&[0] as &[_];
- | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
-
-error[E0605]: non-primitive cast: `u32` as `Option<_>`
- --> $DIR/issue-73886.rs:4:13
- |
-LL | let _ = 7u32 as Option<_>;
- | ^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `Option<_>::from(7u32)`
- |
- = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0605`.
+++ /dev/null
-// compile-flags: -O
-// run-pass
-
-struct Foo {
- x: i32,
-}
-
-pub fn main() {
- let mut foo = Foo { x: 42 };
- let x = &mut foo.x;
- *x = 13;
- let y = foo;
- assert_eq!(y.x, 13); // used to print 42 due to mir-opt bug
-}
+++ /dev/null
-// run-fail
-// error-pattern:quux
-// ignore-emscripten no processes
-
-use std::marker::PhantomData;
-
-fn test00_start(ch: Chan<isize>, message: isize) {
- send(ch, message);
-}
-
-type TaskId = isize;
-type PortId = isize;
-
-struct Chan<T> {
- task: TaskId,
- port: PortId,
- marker: PhantomData<*mut T>,
-}
-
-fn send<T: Send>(_ch: Chan<T>, _data: T) {
- panic!();
-}
-
-fn main() {
- panic!("quux");
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-
-enum E {
- Foo{f: isize},
- Bar,
-}
-
-pub fn main() {
- let e = E::Foo{f: 0};
- match e {
- E::Foo{f: 1} => panic!(),
- E::Foo{..} => (),
- _ => panic!(),
- }
-}
+++ /dev/null
-// run-pass
-#![allow(dead_code)]
-
-enum E {
- Foo{f: isize, b: bool},
- Bar,
-}
-
-pub fn main() {
- let e = E::Foo{f: 0, b: false};
- match e {
- E::Foo{f: 1, b: true} => panic!(),
- E::Foo{b: false, f: 0} => (),
- _ => panic!(),
- }
-}
+++ /dev/null
-use std::fmt::Write;
-
-fn main() {
- println!(b"foo");
- //~^ ERROR format argument must be a string literal
- //~| HELP consider removing the leading `b`
- let mut s = String::new();
- write!(s, b"foo{}", "bar");
- //~^ ERROR format argument must be a string literal
- //~| HELP consider removing the leading `b`
-}
+++ /dev/null
-error: format argument must be a string literal
- --> $DIR/issue-86865.rs:4:14
- |
-LL | println!(b"foo");
- | -^^^^^
- | |
- | help: consider removing the leading `b`
-
-error: format argument must be a string literal
- --> $DIR/issue-86865.rs:8:15
- |
-LL | write!(s, b"foo{}", "bar");
- | -^^^^^^^
- | |
- | help: consider removing the leading `b`
-
-error: aborting due to 2 previous errors
-
+++ /dev/null
-// run-pass
-// ignore-emscripten no threads support
-
-use std::thread;
-use std::sync::mpsc::{channel, Receiver};
-
-fn periodical(n: isize) -> Receiver<bool> {
- let (chan, port) = channel();
- thread::spawn(move|| {
- loop {
- for _ in 1..n {
- match chan.send(false) {
- Ok(()) => {}
- Err(..) => break,
- }
- }
- match chan.send(true) {
- Ok(()) => {}
- Err(..) => break
- }
- }
- });
- return port;
-}
-
-fn integers() -> Receiver<isize> {
- let (chan, port) = channel();
- thread::spawn(move|| {
- let mut i = 1;
- loop {
- match chan.send(i) {
- Ok(()) => {}
- Err(..) => break,
- }
- i = i + 1;
- }
- });
- return port;
-}
-
-fn main() {
- let ints = integers();
- let threes = periodical(3);
- let fives = periodical(5);
- for _ in 1..100 {
- match (ints.recv().unwrap(), threes.recv().unwrap(), fives.recv().unwrap()) {
- (_, true, true) => println!("FizzBuzz"),
- (_, true, false) => println!("Fizz"),
- (_, false, true) => println!("Buzz"),
- (i, false, false) => println!("{}", i)
- }
- }
-}
+++ /dev/null
-// run-pass
-#![allow(unused_must_use)]
-#![allow(deprecated)]
-// ignore-emscripten no threads support
-
-use std::sync::mpsc::{TryRecvError, channel};
-use std::thread;
-
-pub fn main() {
- let (tx, rx) = channel();
- let t = thread::spawn(move||{
- thread::sleep_ms(10);
- tx.send(()).unwrap();
- });
- loop {
- match rx.try_recv() {
- Ok(()) => break,
- Err(TryRecvError::Empty) => {}
- Err(TryRecvError::Disconnected) => unreachable!()
- }
- }
- t.join();
-}
// check-pass
// edition:2021
-// compile-flags: -Zunstable-options
use std::array::IntoIter;
use std::ops::Deref;
+++ /dev/null
-// run-pass
-// shouldn't affect evaluation of $ex:
-macro_rules! bad_macro {
- ($ex:expr) => ({(|_x| { $ex }) (9) })
-}
-
-fn takes_x(_x : isize) {
- assert_eq!(bad_macro!(_x),8);
-}
-fn main() {
- takes_x(8);
-}
--- /dev/null
+// error-pattern: requires `copy` lang_item
+
+#![feature(lang_items, start, no_core)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized { }
+
+struct S;
+
+#[start]
+fn main(_: isize, _: *const *const u8) -> isize {
+ let _ = S;
+ 0
+}
--- /dev/null
+error: requires `copy` lang_item
+
+error: aborting due to previous error
+
--- /dev/null
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized {}
+
+#[lang="add"]
+trait Add<T> {}
+
+impl Add<i32> for i32 {}
+
+fn main() {
+ let x = 5 + 6;
+ //~^ ERROR cannot add `i32` to `{integer}`
+ let y = 5i32 + 6i32;
+ //~^ ERROR cannot add `i32` to `i32`
+}
--- /dev/null
+error[E0369]: cannot add `i32` to `{integer}`
+ --> $DIR/issue-31076.rs:13:15
+ |
+LL | let x = 5 + 6;
+ | - ^ - i32
+ | |
+ | {integer}
+
+error[E0369]: cannot add `i32` to `i32`
+ --> $DIR/issue-31076.rs:15:18
+ |
+LL | let y = 5i32 + 6i32;
+ | ---- ^ ---- i32
+ | |
+ | i32
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0369`.
--- /dev/null
+// build-fail
+
+#![feature(lang_items, no_core)]
+#![no_core]
+
+#[lang="copy"] pub trait Copy { }
+#[lang="sized"] pub trait Sized { }
+
+// error-pattern:requires `start` lang_item
+
+fn main() {}
--- /dev/null
+error: requires `start` lang_item
+
+error: aborting due to previous error
+
+++ /dev/null
-// aux-build:legacy-const-generics.rs
-
-extern crate legacy_const_generics;
-
-fn foo<const N: usize>() {
- let a = 1;
- legacy_const_generics::foo(0, a, 2);
- //~^ ERROR attempt to use a non-constant value in a constant
-
- legacy_const_generics::foo(0, N, 2);
-
- legacy_const_generics::foo(0, N + 1, 2);
- //~^ ERROR generic parameters may not be used in const operations
-}
-
-fn main() {}
+++ /dev/null
-error[E0435]: attempt to use a non-constant value in a constant
- --> $DIR/legacy-const-generics-bad.rs:7:35
- |
-LL | let a = 1;
- | ----- help: consider using `const` instead of `let`: `const a`
-LL | legacy_const_generics::foo(0, a, 2);
- | ^ non-constant value
-
-error: generic parameters may not be used in const operations
- --> $DIR/legacy-const-generics-bad.rs:12:35
- |
-LL | legacy_const_generics::foo(0, N + 1, 2);
- | ^ cannot perform const operation using `N`
- |
- = help: const parameters may only be used as standalone arguments, i.e. `N`
- = help: use `#![feature(generic_const_exprs)]` to allow generic const expressions
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0435`.
+++ /dev/null
-// aux-build:legacy-const-generics.rs
-// run-pass
-
-#![feature(rustc_attrs)]
-
-extern crate legacy_const_generics;
-
-#[rustc_legacy_const_generics(1)]
-pub fn bar<const Y: usize>(x: usize, z: usize) -> [usize; 3] {
- [x, Y, z]
-}
-
-fn main() {
- assert_eq!(legacy_const_generics::foo(0 + 0, 1 + 1, 2 + 2), [0, 2, 4]);
- assert_eq!(legacy_const_generics::foo::<{1 + 1}>(0 + 0, 2 + 2), [0, 2, 4]);
- // FIXME: Only works cross-crate
- //assert_eq!(bar(0, 1, 2), [0, 1, 2]);
-}
--- /dev/null
+fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
+//~^ ERROR missing lifetime specifier [E0106]
+
+fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
+//~^ ERROR missing lifetime specifier [E0106]
+
+fn parse_type_3() -> &str { unimplemented!() }
+//~^ ERROR missing lifetime specifier [E0106]
+
+fn main() {}
--- /dev/null
+error[E0106]: missing lifetime specifier
+ --> $DIR/issue-26638.rs:1:62
+ |
+LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
+ | ------------------------------------ ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say which one of `iter`'s 2 lifetimes it is borrowed from
+help: consider introducing a named lifetime parameter
+ |
+LL | fn parse_type<'a>(iter: Box<dyn Iterator<Item=&str>+'static>) -> &'a str { iter.next() }
+ | ++++ ++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/issue-26638.rs:4:40
+ |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &str { iter() }
+ | ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+help: consider using the `'static` lifetime
+ |
+LL | fn parse_type_2(iter: fn(&u8)->&u8) -> &'static str { iter() }
+ | ~~~~~~~~
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/issue-26638.rs:7:22
+ |
+LL | fn parse_type_3() -> &str { unimplemented!() }
+ | ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+ |
+LL | fn parse_type_3() -> &'static str { unimplemented!() }
+ | ~~~~~~~~
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
--- /dev/null
+// run-rustfix
+
+pub fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+fn main() {}
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/issue-90170-elision-mismatch.rs:3:40
+ |
+LL | pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+ | - - ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+ | | |
+ | | let's call the lifetime of this reference `'1`
+ | let's call the lifetime of this reference `'2`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-90170-elision-mismatch.rs:5:44
+ |
+LL | pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); }
+ | - - ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+ | | |
+ | | let's call the lifetime of this reference `'1`
+ | let's call the lifetime of this reference `'2`
+
+error: lifetime may not live long enough
+ --> $DIR/issue-90170-elision-mismatch.rs:7:63
+ |
+LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+ | - - ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+ | | |
+ | | let's call the lifetime of this reference `'1`
+ | let's call the lifetime of this reference `'2`
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+// run-rustfix
+
+pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); } //~ ERROR lifetime mismatch
+
+fn main() {}
--- /dev/null
+error[E0623]: lifetime mismatch
+ --> $DIR/issue-90170-elision-mismatch.rs:3:47
+ |
+LL | pub fn foo(x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+ | --- --- ^ ...but data from `y` flows into `x` here
+ | |
+ | these two types are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | pub fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+ | ++++ ++ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/issue-90170-elision-mismatch.rs:5:51
+ |
+LL | pub fn foo2(x: &mut Vec<&'_ u8>, y: &u8) { x.push(y); }
+ | ------ --- ^ ...but data from `y` flows into `x` here
+ | |
+ | these two types are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | pub fn foo2<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+ | ++++ ~~ ++
+
+error[E0623]: lifetime mismatch
+ --> $DIR/issue-90170-elision-mismatch.rs:7:70
+ |
+LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&u8>, y: &u8) { x.push(y); }
+ | --- --- ^ ...but data from `y` flows into `x` here
+ | |
+ | these two types are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+ | ++ ++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0623`.
| --- --- these two types are declared with different lifetimes...
LL | *v = x;
| ^ ...but data from `x` flows here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(&mut (ref mut v, w): &mut (&'a u8, &u8), x: &'a u8) {
+ | ++++ ++ ++
error: aborting due to previous error
| --- --- these two types are declared with different lifetimes...
LL | z.push((x,y));
| ^ ...but data flows into `z` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(z: &mut Vec<(&'a u8,&u8)>, (x, y): (&'a u8, &u8)) {
+ | ++++ ++ ++
error[E0623]: lifetime mismatch
--> $DIR/ex3-both-anon-regions-3.rs:2:15
| --- --- these two types are declared with different lifetimes...
LL | z.push((x,y));
| ^ ...but data flows into `z` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(z: &mut Vec<(&u8,&'a u8)>, (x, y): (&u8, &'a u8)) {
+ | ++++ ++ ++
error: aborting due to 2 previous errors
| --- --- these two types are declared with different lifetimes...
LL | y.push(z);
| ^ ...but data from `z` flows into `y` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(x:fn(&u8, &u8), y: Vec<&'a u8>, z: &'a u8) {
+ | ++++ ++ ++
error: aborting due to previous error
| --- --- these two types are declared with different lifetimes...
LL | y.push(z);
| ^ ...but data from `z` flows into `y` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(x:Box<dyn Fn(&'a u8, &'a u8)> , y: Vec<&u8>, z: &u8) {
+ | ++++ ++ ++
error: aborting due to previous error
| --- --- these two types are declared with different lifetimes...
LL | x.push(y);
| ^ ...but data from `y` flows into `x` here
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) {
+ | ++++ ++ ++
error: aborting due to previous error
#![allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
#[allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
const BAR: f64 = 0.000001;
}
#[allow(uncommon_codepoints)]
//~^ ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
+//~| ERROR allow(uncommon_codepoints) is ignored unless specified at crate level [unused_attributes]
fn main() {
}
| ^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:8:9
+ --> $DIR/crate_level_only_lint.rs:9:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:15:9
+ --> $DIR/crate_level_only_lint.rs:17:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:8:9
+ --> $DIR/crate_level_only_lint.rs:9:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
error: allow(uncommon_codepoints) is ignored unless specified at crate level
- --> $DIR/crate_level_only_lint.rs:15:9
+ --> $DIR/crate_level_only_lint.rs:17:9
|
LL | #[allow(uncommon_codepoints)]
| ^^^^^^^^^^^^^^^^^^^
-error: aborting due to 6 previous errors
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:4:10
+ |
+LL | #![allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:9:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: allow(uncommon_codepoints) is ignored unless specified at crate level
+ --> $DIR/crate_level_only_lint.rs:17:9
+ |
+LL | #[allow(uncommon_codepoints)]
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
//~| WARNING previously accepted by the compiler
//~| ERROR incompatible with previous
//~| WARNING previously accepted by the compiler
+//~| ERROR incompatible with previous
+//~| WARNING previously accepted by the compiler
+//~| ERROR incompatible with previous
+//~| WARNING previously accepted by the compiler
+//~| ERROR incompatible with previous
+//~| WARNING previously accepted by the compiler
fn main() {}
= 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 #81670 <https://github.com/rust-lang/rust/issues/81670>
-error: aborting due to 6 previous errors
+error: allow(nonstandard_style) incompatible with previous forbid
+ --> $DIR/forbid-group-group-2.rs:7:9
+ |
+LL | #![forbid(warnings)]
+ | -------- `forbid` level set here
+...
+LL | #[allow(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
+ |
+ = 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 #81670 <https://github.com/rust-lang/rust/issues/81670>
+
+error: allow(nonstandard_style) incompatible with previous forbid
+ --> $DIR/forbid-group-group-2.rs:7:9
+ |
+LL | #![forbid(warnings)]
+ | -------- `forbid` level set here
+...
+LL | #[allow(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
+ |
+ = 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 #81670 <https://github.com/rust-lang/rust/issues/81670>
+
+error: allow(nonstandard_style) incompatible with previous forbid
+ --> $DIR/forbid-group-group-2.rs:7:9
+ |
+LL | #![forbid(warnings)]
+ | -------- `forbid` level set here
+...
+LL | #[allow(nonstandard_style)]
+ | ^^^^^^^^^^^^^^^^^ overruled by previous forbid
+ |
+ = 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 #81670 <https://github.com/rust-lang/rust/issues/81670>
+
+error: aborting due to 9 previous errors
// --force-warn $LINT causes $LINT (which is deny-by-default) to warn
// despite $LINT being allowed on command line
-// compile-flags: -A const_err --force-warn const_err -Zunstable-options
+// compile-flags: -A const_err --force-warn const_err
// check-pass
const C: i32 = 1 / 0;
// --force-warn $LINT_GROUP causes $LINT (which is warn-by-default) to warn
// despite $LINT being allowed on command line
-// compile-flags: -A bare-trait-objects --force-warn rust-2018-idioms -Zunstable-options
+// compile-flags: -A bare-trait-objects --force-warn rust-2018-idioms
// check-pass
pub trait SomeTrait {}
// --force-warn $LINT causes $LINT (which is warn-by-default) to warn
// despite being allowed in one submodule (but not the other)
-// compile-flags: --force-warn dead_code -Zunstable-options
+// compile-flags: --force-warn dead_code
// check-pass
mod one {
// --force-warn warnings is an error
-// compile-flags: --force-warn warnings -Zunstable-options
+// compile-flags: --force-warn warnings
// error-pattern: `warnings` lint group is not supported
fn main() {}
error[E0602]: `warnings` lint group is not supported with ´--force-warn´
-error[E0602]: `warnings` lint group is not supported with ´--force-warn´
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0602`.
--- /dev/null
+// check-pass
+// pretty-expanded FIXME #23616
+
+#[deny(dead_code)]
+pub enum Foo {
+ Bar {
+ baz: isize
+ }
+}
+
+fn main() { }
--- /dev/null
+// check-pass
+
+// Originally from #53925.
+// Tests that the `unreachable_pub` lint doesn't fire for `pub self::bar::Bar`.
+
+#![deny(unreachable_pub)]
+
+mod foo {
+ mod bar {
+ pub struct Bar;
+ }
+
+ pub use self::bar::Bar;
+}
+
+pub use foo::Bar;
+
+fn main() {}
--- /dev/null
+fn part(_: u16) -> u32 {
+ 1
+}
+
+fn main() {
+ for n in 100_000.. {
+ //~^ ERROR: literal out of range for `u16`
+ let _ = part(n);
+ }
+}
--- /dev/null
+error: literal out of range for `u16`
+ --> $DIR/issue-63364.rs:6:14
+ |
+LL | for n in 100_000.. {
+ | ^^^^^^^
+ |
+ = note: `#[deny(overflowing_literals)]` on by default
+ = note: the literal `100_000` does not fit into the type `u16` whose range is `0..=65535`
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+// Allowing the code lint should work without warning and
+// the text flow char in the comment should be ignored.
+
+#![allow(text_direction_codepoint_in_comment)]
+
+fn main() {
+ // U+2066 LEFT-TO-RIGHT ISOLATE follows:
+}
fn main() {
println!("{}", evil!(*(0 as *const u8)));
+ //~^ WARNING dereferencing a null pointer
}
LL | #![forbid(unsafe_code)]
| ^^^^^^^^^^^
-error: aborting due to previous error
+warning: dereferencing a null pointer
+ --> $DIR/lint-forbid-internal-unsafe.rs:15:26
+ |
+LL | println!("{}", evil!(*(0 as *const u8)));
+ | ^^^^^^^^^^^^^^^^^ this code causes undefined behavior when executed
+ |
+ = note: `#[warn(deref_nullptr)]` on by default
+
+error: aborting due to previous error; 1 warning emitted
--- /dev/null
+// edition:2018
+#![deny(must_not_suspend)] //~ ERROR the `must_not_suspend`
+//~| ERROR the `must_not_suspend`
+//~| ERROR the `must_not_suspend`
+
+async fn other() {}
+
+pub async fn uhoh(m: std::sync::Mutex<()>) {
+ let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across
+ other().await;
+}
+
+fn main() {
+}
--- /dev/null
+error[E0658]: the `must_not_suspend` lint is unstable
+ --> $DIR/gated.rs:2:1
+ |
+LL | #![deny(must_not_suspend)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
+ = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
+
+error[E0658]: the `must_not_suspend` lint is unstable
+ --> $DIR/gated.rs:2:1
+ |
+LL | #![deny(must_not_suspend)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
+ = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
+
+error[E0658]: the `must_not_suspend` lint is unstable
+ --> $DIR/gated.rs:2:1
+ |
+LL | #![deny(must_not_suspend)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
+ = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
+
+error: `MutexGuard` held across a suspend point, but should not be
+ --> $DIR/gated.rs:9:9
+ |
+LL | let _guard = m.lock().unwrap();
+ | ^^^^^^
+LL | other().await;
+ | ------------- the value is held across this suspend point
+ |
+note: the lint level is defined here
+ --> $DIR/gated.rs:2:9
+ |
+LL | #![deny(must_not_suspend)]
+ | ^^^^^^^^^^^^^^^^
+note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send`
+ --> $DIR/gated.rs:9:9
+ |
+LL | let _guard = m.lock().unwrap();
+ | ^^^^^^
+help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
+ --> $DIR/gated.rs:9:9
+ |
+LL | let _guard = m.lock().unwrap();
+ | ^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
--- /dev/null
+// edition:2018
+// run-pass
+
+use std::sync::Mutex;
+
+// Copied from the issue. Allow-by-default for now, so run-pass
+pub async fn foo() {
+ let foo = Mutex::new(1);
+ let lock = foo.lock().unwrap();
+
+ // Prevent mutex lock being held across `.await` point.
+ drop(lock);
+
+ bar().await;
+}
+
+async fn bar() {}
+
+fn main() {}
// edition:2018
+#![feature(must_not_suspend)]
#![deny(must_not_suspend)]
async fn other() {}
error: `MutexGuard` held across a suspend point, but should not be
- --> $DIR/mutex.rs:7:9
+ --> $DIR/mutex.rs:8:9
|
LL | let _guard = m.lock().unwrap();
| ^^^^^^
| ------------- the value is held across this suspend point
|
note: the lint level is defined here
- --> $DIR/mutex.rs:2:9
+ --> $DIR/mutex.rs:3:9
|
LL | #![deny(must_not_suspend)]
| ^^^^^^^^^^^^^^^^
note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send`
- --> $DIR/mutex.rs:7:9
+ --> $DIR/mutex.rs:8:9
|
LL | let _guard = m.lock().unwrap();
| ^^^^^^
help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
- --> $DIR/mutex.rs:7:9
+ --> $DIR/mutex.rs:8:9
|
LL | let _guard = m.lock().unwrap();
| ^^^^^^
// edition:2018
// run-pass
#![feature(must_not_suspend)]
+#![warn(must_not_suspend)]
#[must_not_suspend = "You gotta use Umm's, ya know?"]
struct Umm {
warning: `Umm` held across a suspend point, but should not be
- --> $DIR/warn.rs:20:9
+ --> $DIR/warn.rs:21:9
|
LL | let _guard = bar();
| ^^^^^^
LL | other().await;
| ------------- the value is held across this suspend point
|
- = note: `#[warn(must_not_suspend)]` on by default
+note: the lint level is defined here
+ --> $DIR/warn.rs:4:9
+ |
+LL | #![warn(must_not_suspend)]
+ | ^^^^^^^^^^^^^^^^
note: You gotta use Umm's, ya know?
- --> $DIR/warn.rs:20:9
+ --> $DIR/warn.rs:21:9
|
LL | let _guard = bar();
| ^^^^^^
help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
- --> $DIR/warn.rs:20:9
+ --> $DIR/warn.rs:21:9
|
LL | let _guard = bar();
| ^^^^^^
#![deny(uncommon_codepoints)]
const µ: f64 = 0.000001; //~ ERROR identifier contains uncommon Unicode codepoints
+//~| WARNING should have an upper case name
fn dijkstra() {} //~ ERROR identifier contains uncommon Unicode codepoints
| ^^^^^^^^^^^^^^^^^^^
error: identifier contains uncommon Unicode codepoints
- --> $DIR/lint-uncommon-codepoints.rs:5:4
+ --> $DIR/lint-uncommon-codepoints.rs:6:4
|
LL | fn dijkstra() {}
| ^^^^^^^
error: identifier contains uncommon Unicode codepoints
- --> $DIR/lint-uncommon-codepoints.rs:8:9
+ --> $DIR/lint-uncommon-codepoints.rs:9:9
|
LL | let ㇻㇲㇳ = "rust";
| ^^^^^^
-error: aborting due to 3 previous errors
+warning: constant `µ` should have an upper case name
+ --> $DIR/lint-uncommon-codepoints.rs:3:7
+ |
+LL | const µ: f64 = 0.000001;
+ | ^ help: convert the identifier to upper case: `Μ`
+ |
+ = note: `#[warn(non_upper_case_globals)]` on by default
+
+error: aborting due to 3 previous errors; 1 warning emitted
--- /dev/null
+// edition:2018
+
+#![deny(unused_extern_crates)]
+#![feature(test, rustc_private, crate_visibility_modifier)]
+
+extern crate libc;
+//~^ ERROR unused extern crate
+//~| HELP remove
+extern crate libc as x;
+//~^ ERROR unused extern crate
+//~| HELP remove
+
+extern crate proc_macro;
+
+#[macro_use]
+extern crate test;
+
+pub extern crate test as y;
+
+pub extern crate alloc;
+
+pub(crate) extern crate alloc as a;
+
+crate extern crate alloc as b;
+
+mod foo {
+ pub(in crate::foo) extern crate alloc as c;
+
+ pub(super) extern crate alloc as d;
+
+ extern crate libc;
+ //~^ ERROR unused extern crate
+ //~| HELP remove
+
+ extern crate libc as x;
+ //~^ ERROR unused extern crate
+ //~| HELP remove
+
+ pub extern crate test;
+
+ pub extern crate test as y;
+
+ mod bar {
+ extern crate libc;
+ //~^ ERROR unused extern crate
+ //~| HELP remove
+
+ extern crate libc as x;
+ //~^ ERROR unused extern crate
+ //~| HELP remove
+
+ pub(in crate::foo::bar) extern crate alloc as e;
+
+ fn dummy() {
+ e::string::String::new();
+ }
+ }
+
+ fn dummy() {
+ c::string::String::new();
+ d::string::String::new();
+ }
+}
+
+
+fn main() {
+ a::string::String::new();
+ b::string::String::new();
+
+ proc_macro::TokenStream::new();
+}
--- /dev/null
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:6:1
+ |
+LL | extern crate libc;
+ | ^^^^^^^^^^^^^^^^^^ help: remove it
+ |
+note: the lint level is defined here
+ --> $DIR/unnecessary-extern-crate.rs:3:9
+ |
+LL | #![deny(unused_extern_crates)]
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:9:1
+ |
+LL | extern crate libc as x;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
+
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:31:5
+ |
+LL | extern crate libc;
+ | ^^^^^^^^^^^^^^^^^^ help: remove it
+
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:35:5
+ |
+LL | extern crate libc as x;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
+
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:44:9
+ |
+LL | extern crate libc;
+ | ^^^^^^^^^^^^^^^^^^ help: remove it
+
+error: unused extern crate
+ --> $DIR/unnecessary-extern-crate.rs:48:9
+ |
+LL | extern crate libc as x;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
+
+error: aborting due to 6 previous errors
+
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
// run-rustfix
// The output for humans should just highlight the whole span without showing
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
// run-rustfix
// The output for humans should just highlight the whole span without showing
-{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":596,"byte_end":597,"line_start":16,"line_end":16,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));
+{"message":"unnecessary parentheses around assigned value","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":577,"byte_end":578,"line_start":16,"line_end":16,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));
--> $DIR/unused_parens_json_suggestion.rs:16:14
|
LL | let _a = (1 / (2 + 3));
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
// run-rustfix
// The output for humans should just highlight the whole span without showing
-// compile-flags: --error-format json -Zunstable-options
+// compile-flags: --error-format json
// run-rustfix
// The output for humans should just highlight the whole span without showing
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":500,"byte_end":501,"line_start":17,"line_end":17,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) {
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":481,"byte_end":482,"line_start":17,"line_end":17,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (_b) {
--> $DIR/unused_parens_remove_json_suggestion.rs:17:8
|
LL | if (_b) {
|
"}
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":631,"byte_end":632,"line_start":28,"line_end":28,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) {
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":612,"byte_end":613,"line_start":28,"line_end":28,"column_start":7,"column_end":8,"is_primary":true,"text":[{"text":" if(c) {
--> $DIR/unused_parens_remove_json_suggestion.rs:28:7
|
LL | if(c) {
|
"}
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":711,"byte_end":712,"line_start":32,"line_end":32,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":692,"byte_end":693,"line_start":32,"line_end":32,"column_start":8,"column_end":9,"is_primary":true,"text":[{"text":" if (c){
--> $DIR/unused_parens_remove_json_suggestion.rs:32:8
|
LL | if (c){
|
"}
-{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":794,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":793,"byte_end":794,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":807,"byte_end":808,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":774,"byte_end":775,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":788,"byte_end":789,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":774,"byte_end":775,"line_start":36,"line_end":36,"column_start":11,"column_end":12,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":11,"highlight_end":12}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":788,"byte_end":789,"line_start":36,"line_end":36,"column_start":25,"column_end":26,"is_primary":true,"text":[{"text":" while (false && true){","highlight_start":25,"highlight_end":26}],"label":null,"suggested_replacement":" ","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"error: unnecessary parentheses around `while` condition
--> $DIR/unused_parens_remove_json_suggestion.rs:36:11
|
LL | while (false && true){
|
"}
-{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":821,"byte_end":822,"line_start":37,"line_end":37,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) {
+{"message":"unnecessary parentheses around `if` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":802,"byte_end":803,"line_start":37,"line_end":37,"column_start":12,"column_end":13,"is_primary":true,"text":[{"text":" if (c) {
--> $DIR/unused_parens_remove_json_suggestion.rs:37:12
|
LL | if (c) {
|
"}
-{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":918,"byte_end":919,"line_start":43,"line_end":43,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) {
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":899,"byte_end":900,"line_start":43,"line_end":43,"column_start":10,"column_end":11,"is_primary":true,"text":[{"text":" while(true && false) {
--> $DIR/unused_parens_remove_json_suggestion.rs:43:10
|
LL | while(true && false) {
|
"}
-{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":987,"byte_end":988,"line_start":44,"line_end":44,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){
+{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":968,"byte_end":969,"line_start":44,"line_end":44,"column_start":18,"column_end":19,"is_primary":true,"text":[{"text":" for _ in (0 .. 3){
--> $DIR/unused_parens_remove_json_suggestion.rs:44:18
|
LL | for _ in (0 .. 3){
|
"}
-{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1088,"byte_end":1089,"line_start":49,"line_end":49,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {
+{"message":"unnecessary parentheses around `for` iterator expression","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1069,"byte_end":1070,"line_start":49,"line_end":49,"column_start":14,"column_end":15,"is_primary":true,"text":[{"text":" for _ in (0 .. 3) {
--> $DIR/unused_parens_remove_json_suggestion.rs:49:14
|
LL | for _ in (0 .. 3) {
|
"}
-{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1147,"byte_end":1148,"line_start":50,"line_end":50,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) {
+{"message":"unnecessary parentheses around `while` condition","code":{"code":"unused_parens","explanation":null},"level":"error","spans":[{"file_name":"$DIR/unused_parens_remove_json_suggestion.rs","byte_start":1128,"byte_end":1129,"line_start":50,"line_end":50,"column_start":15,"column_end":16,"is_primary":true,"text":[{"text":" while (true && false) {
--> $DIR/unused_parens_remove_json_suggestion.rs:50:15
|
LL | while (true && false) {
--- /dev/null
+// run-pass
+
+#![allow(dead_code)]
+// compile-flags:-D improper-ctypes
+
+// pretty-expanded FIXME #23616
+#![allow(improper_ctypes)]
+
+mod libc {
+ extern "C" {
+ pub fn malloc(size: isize) -> *const u8;
+ }
+}
+
+pub fn main() {}
--- /dev/null
+#![feature(llvm_asm)]
+#![allow(deprecated)] // llvm_asm!
+// compile-flags: -Ccodegen-units=1
+// build-fail
+// only-x86_64
+
+fn main() {
+ unsafe {
+ llvm_asm!("int $3"); //~ ERROR too few operands for instruction
+ //~| ERROR invalid operand in inline asm
+ }
+}
--- /dev/null
+error: invalid operand in inline asm: 'int $3'
+ --> $DIR/issue-23458.rs:9:9
+ |
+LL | llvm_asm!("int $3");
+ | ^
+
+error: too few operands for instruction
+ --> $DIR/issue-23458.rs:9:9
+ |
+LL | llvm_asm!("int $3");
+ | ^
+ |
+note: instantiated into assembly here
+ --> <inline asm>:1:2
+ |
+LL | int
+ | ^
+
+error: aborting due to 2 previous errors
+
--- /dev/null
+// check-pass
+// ignore-emscripten
+
+#![feature(llvm_asm)]
+#![allow(deprecated)] // llvm_asm!
+
+macro_rules! interrupt_handler {
+ () => {
+ unsafe fn _interrupt_handler() {
+ llvm_asm!("pop eax" :::: "intel");
+ }
+ }
+}
+interrupt_handler!{}
+
+fn main() {}
--- /dev/null
+// Regression test for Issue #53787: Fix ICE when creating a label in inline assembler with macros.
+
+// build-fail
+// ignore-emscripten
+
+#![feature(llvm_asm)]
+#![allow(deprecated)] // llvm_asm!
+
+macro_rules! fake_jump {
+ ($id:expr) => {
+ unsafe {
+ llvm_asm!(
+ "
+ jmp $0
+ lea eax, [ebx]
+ xor eax, 0xDEADBEEF
+ retn
+ $0:
+ "::"0"($id)::"volatile", "intel");
+ }
+ };
+}
+
+fn main() {
+ fake_jump!("FirstFunc"); //~ ERROR invalid value for constraint in inline assembly
+ println!("Hello, world!");
+}
--- /dev/null
+error[E0669]: invalid value for constraint in inline assembly
+ --> $DIR/issue-53787-inline-assembler-macro.rs:25:16
+ |
+LL | fake_jump!("FirstFunc");
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0669`.
+++ /dev/null
-// run-pass
-// pretty-expanded FIXME #23616
-
-#![allow(unused_variables)]
-
-pub fn main() {
- let mut i: isize = 0;
- while i < 1000000 {
- i += 1;
- let x = 3;
- }
-}
+++ /dev/null
-// compile-flags: -C lto -C embed-bitcode=no
-
-fn main() {}
+++ /dev/null
-error: options `-C embed-bitcode=no` and `-C lto` are incompatible
-
+++ /dev/null
-// build-fail
-// aux-build:lto-duplicate-symbols1.rs
-// aux-build:lto-duplicate-symbols2.rs
-// error-pattern:Linking globals named 'foo': symbol multiply defined!
-// compile-flags: -C lto
-// no-prefer-dynamic
-
-extern crate lto_duplicate_symbols1;
-extern crate lto_duplicate_symbols2;
-
-fn main() {}
+++ /dev/null
-warning: Linking globals named 'foo': symbol multiply defined!
-
-error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.693a75b4-cgu.0.rcgu.o":
-
-error: aborting due to previous error; 1 warning emitted
-
+++ /dev/null
-// run-pass
-// compile-flags: -C lto -C codegen-units=8
-// no-prefer-dynamic
-
-fn main() {
-}
+++ /dev/null
-// compile-flags: -Clinker-plugin-lto -Copt-level=s
-// build-pass
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-pub fn foo() {}
+++ /dev/null
-// compile-flags: -Clinker-plugin-lto -Copt-level=z
-// build-pass
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-pub fn foo() {}
+++ /dev/null
-// compile-flags: -C lto
-// aux-build:lto-rustc-loads-linker-plugin.rs
-// run-pass
-// no-prefer-dynamic
-
-// This test ensures that if a dependency was compiled with
-// `-Clinker-plugin-lto` then we can compile with `-Clto` and still link against
-// that upstream rlib. This should work because LTO implies we're not actually
-// linking against upstream rlibs since we're generating the object code
-// locally. This test will fail if rustc can't find bytecode in rlibs compiled
-// with `-Clinker-plugin-lto`.
-
-extern crate lto_rustc_loads_linker_plugin;
-
-fn main() {
- lto_rustc_loads_linker_plugin::foo();
-}
+++ /dev/null
-// run-pass
-// compile-flags: -C lto
-// no-prefer-dynamic
-// ignore-emscripten no threads support
-// revisions: mir thir
-// [thir]compile-flags: -Zthir-unsafeck
-
-use std::thread;
-
-static mut HIT: usize = 0;
-
-thread_local!(static A: Foo = Foo);
-
-struct Foo;
-
-impl Drop for Foo {
- fn drop(&mut self) {
- unsafe {
- HIT += 1;
- }
- }
-}
-
-fn main() {
- unsafe {
- assert_eq!(HIT, 0);
- thread::spawn(|| {
- assert_eq!(HIT, 0);
- A.with(|_| ());
- assert_eq!(HIT, 0);
- }).join().unwrap();
- assert_eq!(HIT, 1);
- }
-}
+++ /dev/null
-// compile-flags: -C lto=thin
-// aux-build:lto-rustc-loads-linker-plugin.rs
-// run-pass
-// no-prefer-dynamic
-
-// Same as the adjacent `lto-thin-rustc-loads-linker-plugin.rs` test, only with
-// ThinLTO.
-
-extern crate lto_rustc_loads_linker_plugin;
-
-fn main() {
- lto_rustc_loads_linker_plugin::foo();
-}
--- /dev/null
+// run-pass
+
+// compile-flags: -Clto=thin
+// no-prefer-dynamic
+
+fn main() {
+ println!("hello!");
+}
--- /dev/null
+// compile-flags: -Z thinlto -C codegen-units=8
+
+#[inline]
+pub fn foo(b: u8) {
+ b.to_string();
+}
--- /dev/null
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+#[no_mangle]
+pub extern "C" fn foo() {}
--- /dev/null
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+#[no_mangle]
+pub extern "C" fn foo() {}
--- /dev/null
+// compile-flags: -Clinker-plugin-lto
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
--- /dev/null
+// no-prefer-dynamic
+// compile-flags: -Z thinlto -C codegen-units=8 -C prefer-dynamic
+
+#![crate_type = "rlib"]
+#![crate_type = "dylib"]
+
+pub static A: u32 = 43;
+
+pub mod a {
+ pub static A: u32 = 43;
+}
--- /dev/null
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn bar() -> u32 {
+ 3
+}
--- /dev/null
+// run-pass
+
+// aux-build:dylib.rs
+
+extern crate dylib;
+
+fn main() {
+ dylib::foo(1);
+}
--- /dev/null
+// compile-flags: -C lto -C embed-bitcode=no
+
+fn main() {}
--- /dev/null
+error: options `-C embed-bitcode=no` and `-C lto` are incompatible
+
--- /dev/null
+// build-fail
+// aux-build:lto-duplicate-symbols1.rs
+// aux-build:lto-duplicate-symbols2.rs
+// error-pattern:Linking globals named 'foo': symbol multiply defined!
+// compile-flags: -C lto
+// no-prefer-dynamic
+
+extern crate lto_duplicate_symbols1;
+extern crate lto_duplicate_symbols2;
+
+fn main() {}
--- /dev/null
+warning: Linking globals named 'foo': symbol multiply defined!
+
+error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.693a75b4-cgu.0.rcgu.o":
+
+error: aborting due to previous error; 1 warning emitted
+
--- /dev/null
+// run-pass
+// compile-flags: -C lto -C codegen-units=8
+// no-prefer-dynamic
+
+fn main() {
+}
--- /dev/null
+// compile-flags: -Clinker-plugin-lto -Copt-level=s
+// build-pass
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
--- /dev/null
+// compile-flags: -Clinker-plugin-lto -Copt-level=z
+// build-pass
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn foo() {}
--- /dev/null
+// compile-flags: -C lto
+// aux-build:lto-rustc-loads-linker-plugin.rs
+// run-pass
+// no-prefer-dynamic
+
+// This test ensures that if a dependency was compiled with
+// `-Clinker-plugin-lto` then we can compile with `-Clto` and still link against
+// that upstream rlib. This should work because LTO implies we're not actually
+// linking against upstream rlibs since we're generating the object code
+// locally. This test will fail if rustc can't find bytecode in rlibs compiled
+// with `-Clinker-plugin-lto`.
+
+extern crate lto_rustc_loads_linker_plugin;
+
+fn main() {
+ lto_rustc_loads_linker_plugin::foo();
+}
--- /dev/null
+// run-pass
+// compile-flags: -C lto
+// no-prefer-dynamic
+// ignore-emscripten no threads support
+// revisions: mir thir
+// [thir]compile-flags: -Zthir-unsafeck
+
+use std::thread;
+
+static mut HIT: usize = 0;
+
+thread_local!(static A: Foo = Foo);
+
+struct Foo;
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ unsafe {
+ HIT += 1;
+ }
+ }
+}
+
+fn main() {
+ unsafe {
+ assert_eq!(HIT, 0);
+ thread::spawn(|| {
+ assert_eq!(HIT, 0);
+ A.with(|_| ());
+ assert_eq!(HIT, 0);
+ }).join().unwrap();
+ assert_eq!(HIT, 1);
+ }
+}
--- /dev/null
+// compile-flags: -C lto=thin
+// aux-build:lto-rustc-loads-linker-plugin.rs
+// run-pass
+// no-prefer-dynamic
+
+// Same as the adjacent `lto-thin-rustc-loads-linker-plugin.rs` test, only with
+// ThinLTO.
+
+extern crate lto_rustc_loads_linker_plugin;
+
+fn main() {
+ lto_rustc_loads_linker_plugin::foo();
+}
--- /dev/null
+// run-pass
+
+// aux-build:msvc-imp-present.rs
+// compile-flags: -Z thinlto -C codegen-units=8
+// no-prefer-dynamic
+
+// On MSVC we have a "hack" where we emit symbols that look like `_imp_$name`
+// for all exported statics. This is done because we apply `dllimport` to all
+// imported constants and this allows everything to actually link correctly.
+//
+// The ThinLTO passes aggressively remove symbols if they can, and this test
+// asserts that the ThinLTO passes don't remove these compiler-generated
+// `_imp_*` symbols. The external library that we link in here is compiled with
+// ThinLTO and multiple codegen units and has a few exported constants. Note
+// that we also namely compile the library as both a dylib and an rlib, but we
+// link the rlib to ensure that we assert those generated symbols exist.
+
+extern crate msvc_imp_present as bar;
+
+fn main() {
+ println!("{}", bar::A);
+}
--- /dev/null
+// run-pass
+// compile-flags: -Z thinlto -C codegen-units=2
+
+#[global_allocator]
+static A: std::alloc::System = std::alloc::System;
+
+fn main() {}
--- /dev/null
+// run-pass
+
+// compile-flags: -Z thinlto -C codegen-units=8 -O
+// ignore-emscripten can't inspect instructions on emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+pub fn foo() -> u32 {
+ bar::bar()
+}
+
+mod bar {
+ pub fn bar() -> u32 {
+ 3
+ }
+}
+
+fn main() {
+ println!("{} {}", foo(), bar::bar());
+
+ unsafe {
+ let foo = foo as usize as *const u8;
+ let bar = bar::bar as usize as *const u8;
+
+ assert_eq!(*foo, *bar);
+ }
+}
--- /dev/null
+// run-pass
+
+// compile-flags: -C codegen-units=8 -O -C lto=thin
+// aux-build:thin-lto-inlines-aux.rs
+// no-prefer-dynamic
+// ignore-emscripten can't inspect instructions on emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+extern crate thin_lto_inlines_aux as bar;
+
+pub fn foo() -> u32 {
+ bar::bar()
+}
+
+fn main() {
+ println!("{} {}", foo(), bar::bar());
+
+ unsafe {
+ let foo = foo as usize as *const u8;
+ let bar = bar::bar as usize as *const u8;
+
+ assert_eq!(*foo, *bar);
+ }
+}
--- /dev/null
+// run-pass
+
+// compile-flags: -C codegen-units=8 -Z thinlto
+// ignore-windows
+
+#![feature(linkage)]
+
+pub mod foo {
+ #[linkage = "weak"]
+ #[no_mangle]
+ pub extern "C" fn FOO() -> i32 {
+ 0
+ }
+}
+
+mod bar {
+ extern "C" {
+ fn FOO() -> i32;
+ }
+
+ pub fn bar() -> i32 {
+ unsafe { FOO() }
+ }
+}
+
+fn main() {
+ bar::bar();
+}
+++ /dev/null
-// run-pass
-// Test for a specific corner case: when we compute the LUB of two fn
-// types and their parameters have unbound variables. In that case, we
-// wind up relating those two variables. This was causing an ICE in an
-// in-progress PR.
-
-fn main() {
- let a_f: fn(_) = |_| ();
- let b_f: fn(_) = |_| ();
- let c_f = match 22 {
- 0 => a_f,
- _ => b_f,
- };
- c_f(4);
-}
-error[E0659]: `m` is ambiguous (`macro_rules` vs non-`macro_rules` from other module)
+error[E0659]: `m` is ambiguous
--> $DIR/ambiguity-legacy-vs-modern.rs:31:9
|
LL | m!()
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module
note: `m` could refer to the macro defined here
--> $DIR/ambiguity-legacy-vs-modern.rs:26:5
|
LL | macro m() { 0 }
| ^^^^^^^^^^^^^^^
-error[E0659]: `m` is ambiguous (`macro_rules` vs non-`macro_rules` from other module)
+error[E0659]: `m` is ambiguous
--> $DIR/ambiguity-legacy-vs-modern.rs:43:5
|
LL | m!()
| ^ ambiguous name
|
+ = note: ambiguous because of a conflict between a `macro_rules` name and a non-`macro_rules` name from another module
note: `m` could refer to the macro defined here
--> $DIR/ambiguity-legacy-vs-modern.rs:40:9
|
--- /dev/null
+#![crate_type = "lib"]
+
+#[macro_export]
+macro_rules! mywrite {
+ ($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*)))
+}
--- /dev/null
+macro_rules! prob1 {
+ (0) => {
+ 0
+ };
+ ($n:expr) => {
+ if ($n % 3 == 0) || ($n % 5 == 0) {
+ $n + prob1!($n - 1); //~ ERROR recursion limit reached while expanding `prob1!`
+ } else {
+ prob1!($n - 1);
+ }
+ };
+}
+
+fn main() {
+ println!("Problem 1: {}", prob1!(1000));
+}
--- /dev/null
+error: recursion limit reached while expanding `prob1!`
+ --> $DIR/issue-16098.rs:7:18
+ |
+LL | $n + prob1!($n - 1);
+ | ^^^^^^^^^^^^^^
+...
+LL | println!("Problem 1: {}", prob1!(1000));
+ | ------------ in this macro invocation
+ |
+ = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_16098`)
+ = note: this error originates in the macro `prob1` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
--- /dev/null
+// aux-build:issue-19163.rs
+
+#[macro_use] extern crate issue_19163;
+
+use std::io::Write;
+
+fn main() {
+ let mut v = vec![];
+ mywrite!(&v, "Hello world");
+ //~^ ERROR cannot borrow data in a `&` reference as mutable
+}
--- /dev/null
+error[E0596]: cannot borrow data in a `&` reference as mutable
+ --> $DIR/issue-19163.rs:9:5
+ |
+LL | mywrite!(&v, "Hello world");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable
+ |
+ = note: this error originates in the macro `mywrite` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
--- /dev/null
+#![allow(unused_macros)]
+
+macro_rules! test { ($wrong:t_ty ..) => () }
+ //~^ ERROR: invalid fragment specifier `t_ty`
+
+fn main() {}
--- /dev/null
+error: invalid fragment specifier `t_ty`
+ --> $DIR/issue-21356.rs:3:22
+ |
+LL | macro_rules! test { ($wrong:t_ty ..) => () }
+ | ^^^^^^^^^^^
+ |
+ = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+macro_rules! items {
+ () => {
+ type A = ();
+ fn a() {}
+ }
+}
+
+trait Foo {
+ type A;
+ fn a();
+}
+
+impl Foo for () {
+ items!();
+}
+
+fn main() {
+
+}
--- /dev/null
+macro_rules! foo {
+ ($d:expr) => {{
+ fn bar(d: u8) { }
+ bar(&mut $d);
+ //~^ ERROR mismatched types
+ //~| expected `u8`, found `&mut u8`
+ }}
+}
+
+fn main() {
+ foo!(0u8);
+ //~^ in this expansion of foo!
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-29084.rs:4:13
+ |
+LL | bar(&mut $d);
+ | ^^^^^^^ expected `u8`, found `&mut u8`
+...
+LL | foo!(0u8);
+ | --------- in this macro invocation
+ |
+ = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-pass
+
+macro_rules! null { ($i:tt) => {} }
+macro_rules! apply_null {
+ ($i:item) => { null! { $i } }
+}
+
+fn main() {
+ apply_null!(#[cfg(all())] fn f() {});
+}
--- /dev/null
+// run-pass
+macro_rules! m { (<$t:ty>) => { stringify!($t) } }
+fn main() {
+ println!("{}", m!(<Vec<i32>>));
+}
--- /dev/null
+#![allow(unused_macros)]
+
+macro_rules! assign {
+ (($($a:tt)*) = ($($b:tt))*) => { //~ ERROR expected one of: `*`, `+`, or `?`
+ $($a)* = $($b)*
+ }
+}
+
+fn main() {}
--- /dev/null
+error: expected one of: `*`, `+`, or `?`
+ --> $DIR/issue-39388.rs:4:22
+ |
+LL | (($($a:tt)*) = ($($b:tt))*) => {
+ | ^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+#![allow(unused_macros)]
+macro_rules! m {
+ ($e:expr) => {
+ macro_rules! n { () => { $e } }
+ }
+}
+
+fn main() {
+ m!(foo!());
+}
--- /dev/null
+// Regression test for #57597.
+//
+// Make sure that nested matchers work correctly rather than causing an infinite loop or crash.
+
+// edition:2018
+
+macro_rules! foo1 {
+ ($($($i:ident)?)+) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo2 {
+ ($($($i:ident)?)*) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo3 {
+ ($($($i:ident)?)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo4 {
+ ($($($($i:ident)?)?)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo5 {
+ ($($($($i:ident)*)?)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo6 {
+ ($($($($i:ident)?)*)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo7 {
+ ($($($($i:ident)?)?)*) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo8 {
+ ($($($($i:ident)*)*)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo9 {
+ ($($($($i:ident)?)*)*) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo10 {
+ ($($($($i:ident)?)*)+) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo11 {
+ ($($($($i:ident)+)?)*) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+macro_rules! foo12 {
+ ($($($($i:ident)+)*)?) => {};
+ //~^ ERROR repetition matches empty token tree
+}
+
+fn main() {
+ foo1!();
+ foo2!();
+ foo3!();
+ foo4!();
+ foo5!();
+ foo6!();
+ foo7!();
+ foo8!();
+ foo9!();
+ foo10!();
+ foo11!();
+ foo12!();
+}
--- /dev/null
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:8:7
+ |
+LL | ($($($i:ident)?)+) => {};
+ | ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:13:7
+ |
+LL | ($($($i:ident)?)*) => {};
+ | ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:18:7
+ |
+LL | ($($($i:ident)?)?) => {};
+ | ^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:23:7
+ |
+LL | ($($($($i:ident)?)?)?) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:28:7
+ |
+LL | ($($($($i:ident)*)?)?) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:33:7
+ |
+LL | ($($($($i:ident)?)*)?) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:38:7
+ |
+LL | ($($($($i:ident)?)?)*) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:43:7
+ |
+LL | ($($($($i:ident)*)*)?) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:48:7
+ |
+LL | ($($($($i:ident)?)*)*) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:53:7
+ |
+LL | ($($($($i:ident)?)*)+) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:58:7
+ |
+LL | ($($($($i:ident)+)?)*) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: repetition matches empty token tree
+ --> $DIR/issue-57597.rs:63:7
+ |
+LL | ($($($($i:ident)+)*)?) => {};
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 12 previous errors
+
--- /dev/null
+macro_rules! e {
+ ($inp:ident) => (
+ $nonexistent
+ //~^ ERROR expected expression, found `$`
+ );
+}
+
+fn main() {
+ e!(foo);
+}
--- /dev/null
+error: expected expression, found `$`
+ --> $DIR/issue-6596-1.rs:3:9
+ |
+LL | $nonexistent
+ | ^^^^^^^^^^^^ expected expression
+...
+LL | e!(foo);
+ | ------- in this macro invocation
+ |
+ = note: this error originates in the macro `e` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
--- /dev/null
+use std::fmt::Write;
+
+fn main() {
+ println!(b"foo");
+ //~^ ERROR format argument must be a string literal
+ //~| HELP consider removing the leading `b`
+ let mut s = String::new();
+ write!(s, b"foo{}", "bar");
+ //~^ ERROR format argument must be a string literal
+ //~| HELP consider removing the leading `b`
+}
--- /dev/null
+error: format argument must be a string literal
+ --> $DIR/issue-86865.rs:4:14
+ |
+LL | println!(b"foo");
+ | -^^^^^
+ | |
+ | help: consider removing the leading `b`
+
+error: format argument must be a string literal
+ --> $DIR/issue-86865.rs:8:15
+ |
+LL | write!(s, b"foo{}", "bar");
+ | -^^^^^^^
+ | |
+ | help: consider removing the leading `b`
+
+error: aborting due to 2 previous errors
+
-error[E0659]: `std` is ambiguous (glob import vs any other name from outer scope during import/macro resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/macro-path-prelude-shadowing.rs:29:9
|
LL | std::panic!();
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution
= note: `std` could refer to a built-in crate
note: `std` could also refer to the module imported here
--> $DIR/macro-path-prelude-shadowing.rs:27:9
= note: macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)
= note: this error originates in the macro `m1` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `foo` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `foo` is ambiguous
--> $DIR/macro-shadowing.rs:17:1
|
LL | foo!();
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `foo` could refer to the macro defined here
--> $DIR/macro-shadowing.rs:10:5
|
-error[E0659]: `bar` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `bar` is ambiguous
--> $DIR/out-of-order-shadowing.rs:5:1
|
LL | bar!();
| ^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `bar` could refer to the macro defined here
--> $DIR/out-of-order-shadowing.rs:4:1
|
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:101:13
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:139:42
|
LL | macro_rules! gen_invoc { () => { m!() } }
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:148:9
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:164:9
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:180:13
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:218:42
|
LL | macro_rules! gen_invoc { () => { m!() } }
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:232:9
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-legacy.rs:262:42
|
LL | macro_rules! gen_invoc { () => { m!() } }
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-legacy.rs:88:9
|
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:104:17
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:147:33
|
LL | macro gen_invoc() { m!() }
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:156:13
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:172:13
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:190:17
|
LL | m!();
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
| ---------- in this macro invocation
= note: this error originates in the macro `gen_gen_inner_invoc` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `m` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `m` is ambiguous
--> $DIR/restricted-shadowing-modern.rs:233:33
|
LL | macro gen_invoc() { m!() }
LL | include!();
| ---------- in this macro invocation
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `m` could refer to the macro defined here
--> $DIR/restricted-shadowing-modern.rs:91:9
|
--- /dev/null
+#![feature(trace_macros)]
+
+fn main() {
+ trace_macros!(); //~ ERROR trace_macros! accepts only `true` or `false`
+ trace_macros!(1); //~ ERROR trace_macros! accepts only `true` or `false`
+ trace_macros!(ident); //~ ERROR trace_macros! accepts only `true` or `false`
+ trace_macros!(for); //~ ERROR trace_macros! accepts only `true` or `false`
+ trace_macros!(true,); //~ ERROR trace_macros! accepts only `true` or `false`
+ trace_macros!(false 1); //~ ERROR trace_macros! accepts only `true` or `false`
+
+
+ // should be fine:
+ macro_rules! expando {
+ ($x: ident) => { trace_macros!($x) }
+ }
+
+ expando!(true);
+}
--- /dev/null
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:4:5
+ |
+LL | trace_macros!();
+ | ^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:5:5
+ |
+LL | trace_macros!(1);
+ | ^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:6:5
+ |
+LL | trace_macros!(ident);
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:7:5
+ |
+LL | trace_macros!(for);
+ | ^^^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:8:5
+ |
+LL | trace_macros!(true,);
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: trace_macros! accepts only `true` or `false`
+ --> $DIR/trace_macros-format.rs:9:5
+ |
+LL | trace_macros!(false 1);
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
--- /dev/null
+// run-pass
+
+#![feature(marker_trait_attr)]
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
+
+#[marker]
+trait MyMarker {}
+
+impl<T> MyMarker for T {}
+impl<T> MyMarker for Vec<T> {}
+
+fn foo<T: MyMarker>(t: T) -> T {
+ t
+}
+
+fn main() {
+ assert_eq!(1, foo(1));
+ assert_eq!(2.0, foo(2.0));
+ assert_eq!(vec![1], foo(vec![1]));
+}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/overlap-doesnt-conflict-with-specialization.rs:4:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+ = help: consider using `min_specialization` instead, which is more stable and complete
+
+warning: 1 warning emitted
+
--- /dev/null
+// run-pass
+// Tests for RFC 1268: we allow overlapping impls of marker traits,
+// that is, traits with #[marker]. In this case, a type `T` is
+// `MyMarker` if it is either `Debug` or `Display`.
+
+#![feature(marker_trait_attr)]
+
+use std::fmt::{Debug, Display};
+
+#[marker] trait MyMarker {}
+
+impl<T: Debug> MyMarker for T {}
+impl<T: Display> MyMarker for T {}
+
+fn foo<T: MyMarker>(t: T) -> T {
+ t
+}
+
+fn main() {
+ // Debug && Display:
+ assert_eq!(1, foo(1));
+ assert_eq!(2.0, foo(2.0));
+
+ // Debug && !Display:
+ assert_eq!(vec![1], foo(vec![1]));
+}
--- /dev/null
+// run-pass
+
+const TEST_STR: &'static str = "abcd";
+
+fn main() {
+ let s = "abcd";
+ match s {
+ TEST_STR => (),
+ _ => unreachable!()
+ }
+}
--- /dev/null
+// run-pass
+// Regression test for #18060: match arms were matching in the wrong order.
+
+fn main() {
+ assert_eq!(2, match (1, 3) { (0, 2..=5) => 1, (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 });
+ assert_eq!(2, match (1, 3) { (1, 3) => 2, (_, 2..=5) => 3, (_, _) => 4 });
+ assert_eq!(2, match (1, 7) { (0, 2..=5) => 1, (1, 7) => 2, (_, 2..=5) => 3, (_, _) => 4 });
+}
--- /dev/null
+// run-pass
+#![allow(overlapping_range_endpoints)]
+
+fn main() {
+ let x = 'a';
+
+ let y = match x {
+ 'a'..='b' if false => "one",
+ 'a' => "two",
+ 'a'..='b' => "three",
+ _ => panic!("what?"),
+ };
+
+ assert_eq!(y, "two");
+}
--- /dev/null
+// run-pass
+
+// This test is bogus (i.e., should be check-fail) during the period
+// where #54986 is implemented and #54987 is *not* implemented. For
+// now: just ignore it
+//
+// ignore-test
+
+// This test is checking that the write to `c.0` (which has been moved out of)
+// won't overwrite the state in `c2`.
+//
+// That's a fine thing to test when this code is accepted by the
+// compiler, and this code is being transcribed accordingly into
+// the ui test issue-21232-partial-init-and-use.rs
+
+fn main() {
+ let mut c = (1, "".to_owned());
+ match c {
+ c2 => {
+ c.0 = 2;
+ assert_eq!(c2.0, 1);
+ }
+ }
+}
--- /dev/null
+// run-pass
+#![feature(box_syntax)]
+#![feature(box_patterns)]
+
+#[derive(Debug, PartialEq)]
+enum Test {
+ Foo(usize),
+ Bar(isize),
+}
+
+fn main() {
+ let a = box Test::Foo(10);
+ let b = box Test::Bar(-20);
+ match (a, b) {
+ (_, box Test::Foo(_)) => unreachable!(),
+ (box Test::Foo(x), b) => {
+ assert_eq!(x, 10);
+ assert_eq!(b, box Test::Bar(-20));
+ },
+ _ => unreachable!(),
+ }
+}
// run-pass
// edition:2021
-// compile-flags: -Zunstable-options
// regression test for https://github.com/rust-lang/rust/pull/85678
+++ /dev/null
-// compile-flags: -Zunleash-the-miri-inside-of-you
-
-// This test demonstrates a shortcoming of the `MaybeMutBorrowedLocals` analysis. It does not
-// handle code that takes a reference to one field of a struct, then use pointer arithmetic to
-// transform it to another field of that same struct that may have interior mutability. For now,
-// this is UB, but this may change in the future. See [rust-lang/unsafe-code-guidelines#134].
-//
-// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
-
-#![feature(core_intrinsics, rustc_attrs, const_raw_ptr_deref)]
-
-use std::cell::UnsafeCell;
-use std::intrinsics::rustc_peek;
-
-#[repr(C)]
-struct PartialInteriorMut {
- zst: [i32; 0],
- cell: UnsafeCell<i32>,
-}
-
-#[rustc_mir(rustc_peek_indirectly_mutable,stop_after_dataflow)]
-const BOO: i32 = {
- let x = PartialInteriorMut {
- zst: [],
- cell: UnsafeCell::new(0),
- };
-
- let p_zst: *const _ = &x.zst ; // Doesn't cause `x` to get marked as indirectly mutable.
-
- let rmut_cell = unsafe {
- // Take advantage of the fact that `zst` and `cell` are at the same location in memory.
- // This trick would work with any size type if miri implemented `ptr::offset`.
- let p_cell = p_zst as *const UnsafeCell<i32>;
-
- let pmut_cell = (*p_cell).get();
- &mut *pmut_cell
- };
-
- *rmut_cell = 42; // Mutates `x` indirectly even though `x` is not marked indirectly mutable!!!
- let val = *rmut_cell;
- rustc_peek(x); //~ ERROR rustc_peek: bit not set
-
- val
-};
-
-fn main() {
- println!("{}", BOO);
-}
+++ /dev/null
-error: rustc_peek: bit not set
- --> $DIR/indirect-mutation-offset.rs:41:5
- |
-LL | rustc_peek(x);
- | ^^^^^^^^^^^^^
-
-error: stop_after_dataflow ended compilation
-
-error: aborting due to 2 previous errors
-
--- /dev/null
+// compile-flags: -O
+// run-pass
+
+struct Foo {
+ x: i32,
+}
+
+pub fn main() {
+ let mut foo = Foo { x: 42 };
+ let x = &mut foo.x;
+ *x = 13;
+ let y = foo;
+ assert_eq!(y.x, 13); // used to print 42 due to mir-opt bug
+}
+++ /dev/null
-// run-pass
-// pretty-expanded FIXME #23616
-
-pub fn main() {
- let _x: &mut [isize] = &mut [ 1, 2, 3 ];
-}
error[E0277]: `NoSync` cannot be shared between threads safely
- --> $DIR/mutable-enum-indirect.rs:17:5
+ --> $DIR/mutable-enum-indirect.rs:17:9
|
LL | bar(&x);
- | ^^^ `NoSync` cannot be shared between threads safely
+ | --- ^^ `NoSync` cannot be shared between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `&Foo`, the trait `Sync` is not implemented for `NoSync`
note: required because it appears within the type `Foo`
+++ /dev/null
-// run-pass
-
-pub fn main() {
- match -5 {
- -5 => {}
- _ => { panic!() }
- }
-}
+++ /dev/null
-// run-pass
-// aux-build:nested_item.rs
-
-
-extern crate nested_item;
-
-pub fn main() {
- assert_eq!(2, nested_item::foo::<()>());
- assert_eq!(2, nested_item::foo::<isize>());
-}
--- /dev/null
+// After #39485, this test used to pass, but that change was reverted
+// due to numerous inference failures like #39808, so it now fails
+// again. #39485 made it so that diverging types never propagate
+// upward; but we now do propagate such types upward in many more
+// cases.
+
+fn g() {
+ &panic!() //~ ERROR mismatched types
+}
+
+fn f() -> isize {
+ (return 1, return 2) //~ ERROR mismatched types
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/diverging-tuple-parts-39485.rs:8:5
+ |
+LL | &panic!()
+ | ^^^^^^^^^ expected `()`, found reference
+ |
+ = note: expected unit type `()`
+ found reference `&_`
+help: try adding a return type
+ |
+LL | fn g() -> &_ {
+ | +++++
+help: consider removing the borrow
+ |
+LL - &panic!()
+LL + panic!()
+ |
+
+error[E0308]: mismatched types
+ --> $DIR/diverging-tuple-parts-39485.rs:12:5
+ |
+LL | fn f() -> isize {
+ | ----- expected `isize` because of return type
+LL | (return 1, return 2)
+ | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found tuple
+ |
+ = note: expected type `isize`
+ found tuple `(!, !)`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// run-pass
-
-fn f(x: Box<isize>) {
- let y: &isize = &*x;
- println!("{}", *x);
- println!("{}", *y);
-}
-
-trait Trait {
- fn printme(&self);
-}
-
-struct Struct;
-
-impl Trait for Struct {
- fn printme(&self) {
- println!("hello world!");
- }
-}
-
-fn g(x: Box<dyn Trait>) {
- x.printme();
- let y: &dyn Trait = &*x;
- y.printme();
-}
-
-fn main() {
- f(Box::new(1234));
- g(Box::new(Struct) as Box<dyn Trait>);
-}
+++ /dev/null
-// run-pass
-
-#![allow(improper_ctypes)]
-#![allow(dead_code)]
-// Issue #901
-// pretty-expanded FIXME #23616
-
-mod libc {
- extern "C" {
- pub fn printf(x: ());
- }
-}
-
-pub fn main() {}
error[E0277]: `NoSend` cannot be sent between threads safely
- --> $DIR/no_send-enum.rs:16:5
+ --> $DIR/no_send-enum.rs:16:9
|
LL | bar(x);
- | ^^^ `NoSend` cannot be sent between threads safely
+ | --- ^ `NoSend` cannot be sent between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `Foo`, the trait `Send` is not implemented for `NoSend`
note: required because it appears within the type `Foo`
error[E0277]: `NoSync` cannot be shared between threads safely
- --> $DIR/no_share-enum.rs:14:5
+ --> $DIR/no_share-enum.rs:14:9
|
LL | bar(x);
- | ^^^ `NoSync` cannot be shared between threads safely
+ | --- ^ `NoSync` cannot be shared between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `Foo`, the trait `Sync` is not implemented for `NoSync`
note: required because it appears within the type `Foo`
--- /dev/null
+// run-pass
+
+pub fn main() {
+ let a = 1;
+ let a_neg: i8 = -a;
+ println!("{}", a_neg);
+
+ let b = 1;
+ let b_neg: i16 = -b;
+ println!("{}", b_neg);
+
+ let c = 1;
+ let c_neg: i32 = -c;
+ println!("{}", c_neg);
+
+ let d = 1;
+ let d_neg: i64 = -d;
+ println!("{}", d_neg);
+
+ let e = 1;
+ let e_neg: isize = -e;
+ println!("{}", e_neg);
+}
+++ /dev/null
-// Test that an object type `Box<Foo>` is not considered to implement the
-// trait `Foo`. Issue #5087.
-
-trait Foo {}
-fn take_foo<F:Foo>(f: F) {}
-fn take_object(f: Box<dyn Foo>) { take_foo(f); }
-//~^ ERROR `Box<dyn Foo>: Foo` is not satisfied
-fn main() {}
+++ /dev/null
-error[E0277]: the trait bound `Box<dyn Foo>: Foo` is not satisfied
- --> $DIR/object-does-not-impl-trait.rs:6:44
- |
-LL | fn take_object(f: Box<dyn Foo>) { take_foo(f); }
- | -------- ^ the trait `Foo` is not implemented for `Box<dyn Foo>`
- | |
- | required by a bound introduced by this call
- |
-note: required by a bound in `take_foo`
- --> $DIR/object-does-not-impl-trait.rs:5:15
- |
-LL | fn take_foo<F:Foo>(f: F) {}
- | ^^^ required by this bound in `take_foo`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0277`.
+++ /dev/null
-// run-pass
-
-#![feature(marker_trait_attr)]
-#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
-
-#[marker]
-trait MyMarker {}
-
-impl<T> MyMarker for T {}
-impl<T> MyMarker for Vec<T> {}
-
-fn foo<T: MyMarker>(t: T) -> T {
- t
-}
-
-fn main() {
- assert_eq!(1, foo(1));
- assert_eq!(2.0, foo(2.0));
- assert_eq!(vec![1], foo(vec![1]));
-}
+++ /dev/null
-warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/overlap-doesnt-conflict-with-specialization.rs:4:12
- |
-LL | #![feature(specialization)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
- = help: consider using `min_specialization` instead, which is more stable and complete
-
-warning: 1 warning emitted
-
+++ /dev/null
-// run-pass
-// Tests for RFC 1268: we allow overlapping impls of marker traits,
-// that is, traits with #[marker]. In this case, a type `T` is
-// `MyMarker` if it is either `Debug` or `Display`.
-
-#![feature(marker_trait_attr)]
-
-use std::fmt::{Debug, Display};
-
-#[marker] trait MyMarker {}
-
-impl<T: Debug> MyMarker for T {}
-impl<T: Display> MyMarker for T {}
-
-fn foo<T: MyMarker>(t: T) -> T {
- t
-}
-
-fn main() {
- // Debug && Display:
- assert_eq!(1, foo(1));
- assert_eq!(2.0, foo(2.0));
-
- // Debug && !Display:
- assert_eq!(vec![1], foo(vec![1]));
-}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![feature(unsize, coerce_unsized)]
+
+#[repr(packed)]
+struct UnalignedPtr<'a, T: ?Sized>
+ where T: 'a,
+{
+ data: &'a T,
+}
+
+fn main() {
+
+ impl<'a, T, U> std::ops::CoerceUnsized<UnalignedPtr<'a, U>> for UnalignedPtr<'a, T>
+ where
+ T: std::marker::Unsize<U> + ?Sized,
+ U: ?Sized,
+ { }
+
+ let arr = [1, 2, 3];
+ let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr };
+ let arr_unaligned: UnalignedPtr<[i32]> = arr_unaligned;
+}
--- /dev/null
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(ICE)]
+pub fn derive(_: TokenStream) -> TokenStream {
+ r#"#[allow(missing_docs)] struct X { }"#.parse().unwrap()
+}
--- /dev/null
+// check-pass
+
+// Bastion of the Turbofish
+// ------------------------
+// Beware travellers, lest you venture into waters callous and unforgiving,
+// where hope must be abandoned, ere it is cruelly torn from you. For here
+// stands the bastion of the Turbofish: an impenetrable fortress holding
+// unshaking against those who would dare suggest the supererogation of the
+// Turbofish.
+//
+// Once I was young and foolish and had the impudence to imagine that I could
+// shake free from the coils by which that creature had us tightly bound. I
+// dared to suggest that there was a better way: a brighter future, in which
+// Rustaceans both new and old could be rid of that vile beast. But alas! In
+// my foolhardiness my ignorance was unveiled and my dreams were dashed
+// unforgivingly against the rock of syntactic ambiguity.
+//
+// This humble program, small and insignificant though it might seem,
+// demonstrates that to which we had previously cast a blind eye: an ambiguity
+// in permitting generic arguments to be provided without the consent of the
+// Great Turbofish. Should you be so naïve as to try to revolt against its
+// mighty clutches, here shall its wrath be indomitably displayed. This
+// program must pass for all eternity: forever watched by the guardian angel
+// which gave this beast its name, and stands fundamentally at odds with the
+// impetuous rebellion against the Turbofish.
+//
+// My heart aches in sorrow, for I know I am defeated. Let this be a warning
+// to all those who come after: for they too must overcome the impassible
+// hurdle of defeating the great beast, championed by a resolute winged
+// guardian.
+//
+// Here stands the Bastion of the Turbofish, a memorial to Anna Harren,
+// Guardian Angel of these Hallowed Grounds. <3
+
+// See https://github.com/rust-lang/rust/pull/53562
+// and https://github.com/rust-lang/rfcs/pull/2527
+// and https://twitter.com/garblefart/status/1393236602856611843
+// for context.
+
+fn main() {
+ let (the, guardian, stands, resolute) = ("the", "Turbofish", "remains", "undefeated");
+ let _: (bool, bool) = (the<guardian, stands>(resolute));
+}
--- /dev/null
+fn main() {
+ if true {
+ } else if { //~ ERROR missing condition
+ //~^ ERROR mismatched types
+ } else {
+ }
+}
+
+fn foo() {
+ if true {
+ } else if { //~ ERROR missing condition
+ //~^ ERROR mismatched types
+ }
+ bar();
+}
+
+fn bar() {}
--- /dev/null
+error: missing condition for `if` expression
+ --> $DIR/issue-13483.rs:3:14
+ |
+LL | } else if {
+ | ^ expected if condition here
+
+error: missing condition for `if` expression
+ --> $DIR/issue-13483.rs:11:14
+ |
+LL | } else if {
+ | ^ expected if condition here
+
+error[E0308]: mismatched types
+ --> $DIR/issue-13483.rs:3:15
+ |
+LL | } else if {
+ | _______________^
+LL | |
+LL | | } else {
+ | |_____^ expected `bool`, found `()`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-13483.rs:11:15
+ |
+LL | } else if {
+ | _______________^
+LL | |
+LL | | }
+ | |_____^ expected `bool`, found `()`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// We need all these 9 issue-20616-N.rs files
+// because we can only catch one parsing error at a time
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+type Type_4<T> = Type_1_<'static,, T>;
+//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /dev/null
+error: expected one of `>`, a const expression, lifetime, or type, found `,`
+ --> $DIR/issue-20616-4.rs:16:34
+ |
+LL | type Type_4<T> = Type_1_<'static,, T>;
+ | ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to previous error
+
--- /dev/null
+// We need all these 9 issue-20616-N.rs files
+// because we can only catch one parsing error at a time
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+type Type_5<'a> = Type_1_<'a, (),,>;
+//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /dev/null
+error: expected one of `>`, a const expression, lifetime, or type, found `,`
+ --> $DIR/issue-20616-5.rs:22:34
+ |
+LL | type Type_5<'a> = Type_1_<'a, (),,>;
+ | ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to previous error
+
--- /dev/null
+// We need all these 9 issue-20616-N.rs files
+// because we can only catch one parsing error at a time
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+type Type_6 = Type_5_<'a,,>;
+//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
+
+
+//type Type_7 = Box<(),,>; // error: expected type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /dev/null
+error: expected one of `>`, a const expression, lifetime, or type, found `,`
+ --> $DIR/issue-20616-6.rs:25:26
+ |
+LL | type Type_6 = Type_5_<'a,,>;
+ | ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to previous error
+
--- /dev/null
+// We need all these 9 issue-20616-N.rs files
+// because we can only catch one parsing error at a time
+
+type Type_1_<'a, T> = &'a T;
+
+
+//type Type_1<'a T> = &'a T; // error: expected `,` or `>` after lifetime name, found `T`
+
+
+//type Type_2 = Type_1_<'static ()>; // error: expected `,` or `>` after lifetime name, found `(`
+
+
+//type Type_3<T> = Box<T,,>; // error: expected type, found `,`
+
+
+//type Type_4<T> = Type_1_<'static,, T>; // error: expected type, found `,`
+
+
+type Type_5_<'a> = Type_1_<'a, ()>;
+
+
+//type Type_5<'a> = Type_1_<'a, (),,>; // error: expected type, found `,`
+
+
+//type Type_6 = Type_5_<'a,,>; // error: expected type, found `,`
+
+
+type Type_7 = Box<(),,>;
+//~^ error: expected one of `>`, a const expression, lifetime, or type, found `,`
+
+
+//type Type_8<'a,,> = &'a (); // error: expected ident, found `,`
+
+
+//type Type_9<T,,> = Box<T>; // error: expected ident, found `,`
--- /dev/null
+error: expected one of `>`, a const expression, lifetime, or type, found `,`
+ --> $DIR/issue-20616-7.rs:28:22
+ |
+LL | type Type_7 = Box<(),,>;
+ | ^ expected one of `>`, a const expression, lifetime, or type
+
+error: aborting due to previous error
+
--- /dev/null
+// run-pass
+#![allow(unused_imports, overlapping_range_endpoints)]
+// pretty-expanded FIXME #23616
+
+use m::{START, END};
+
+fn main() {
+ match 42 {
+ m::START..=m::END => {},
+ 0..=m::END => {},
+ m::START..=59 => {},
+ _ => {},
+ }
+}
+
+mod m {
+ pub const START: u32 = 4;
+ pub const END: u32 = 14;
+}
--- /dev/null
+// Test that error recovery in the parser to an EOF does not give an infinite
+// spew of errors.
+
+fn main() {
+ let
+} //~ ERROR expected pattern, found `}`
--- /dev/null
+error: expected pattern, found `}`
+ --> $DIR/issue-31804.rs:6:1
+ |
+LL | }
+ | ^ expected pattern
+
+error: aborting due to previous error
+
--- /dev/null
+enum Test {
+ Drill {
+ field: i32,
+ }
+}
+
+fn main() {
+ Test::Drill(field: 42);
+ //~^ ERROR invalid `struct` delimiters or `fn` call arguments
+}
--- /dev/null
+error: invalid `struct` delimiters or `fn` call arguments
+ --> $DIR/issue-34255-1.rs:8:5
+ |
+LL | Test::Drill(field: 42);
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: if `Test::Drill` is a struct, use braces as delimiters
+ |
+LL | Test::Drill { field: 42 };
+ | ~ ~
+help: if `Test::Drill` is a function, use the arguments directly
+ |
+LL - Test::Drill(field: 42);
+LL + Test::Drill(42);
+ |
+
+error: aborting due to previous error
+
--- /dev/null
+#![allow(unused_variables)]; //~ ERROR expected item, found `;`
+//~^ ERROR `main` function
+fn foo() {}
--- /dev/null
+error: expected item, found `;`
+ --> $DIR/issue-49040.rs:1:28
+ |
+LL | #![allow(unused_variables)];
+ | ^ help: remove this semicolon
+
+error[E0601]: `main` function not found in crate `issue_49040`
+ --> $DIR/issue-49040.rs:1:1
+ |
+LL | #![allow(unused_variables)];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ consider adding a `main` function to `$DIR/issue-49040.rs`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
--- /dev/null
+struct T;
+
+impl for T {}
+//~^ ERROR missing trait in a trait impl
+
+fn main() {}
--- /dev/null
+error: missing trait in a trait impl
+ --> $DIR/issue-56031.rs:3:5
+ |
+LL | impl for T {}
+ | ^
+ |
+help: add a trait here
+ |
+LL | impl Trait for T {}
+ | +++++
+help: for an inherent impl, drop this `for`
+ |
+LL - impl for T {}
+LL + impl T {}
+ |
+
+error: aborting due to previous error
+
--- /dev/null
+// aux-build:issue-89971-outer-attr-following-inner-attr-ice.rs
+
+#[macro_use]
+extern crate issue_89971_outer_attr_following_inner_attr_ice;
+
+fn main() {
+ Mew();
+ X {};
+}
+
+#![deny(missing_docs)]
+//~^ ERROR an inner attribute is not permitted in this context
+#[derive(ICE)]
+#[deny(missing_docs)]
+struct Mew();
--- /dev/null
+error: an inner attribute is not permitted in this context
+ --> $DIR/issue-89971-outer-attr-following-inner-attr-ice.rs:11:1
+ |
+LL | #![deny(missing_docs)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | struct Mew();
+ | ------------- the inner attribute doesn't annotate this struct
+ |
+ = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+help: to annotate the struct, change the attribute from inner to outer style
+ |
+LL - #![deny(missing_docs)]
+LL + #[deny(missing_docs)]
+ |
+
+error: aborting due to previous error
+
--- /dev/null
+fn main() {
+ // if access_level != "user" { // Check if admin
+ //~^ ERROR unicode codepoint changing visible direction of text present in comment
+ println!("us\u{202B}e\u{202A}r");
+ println!("{:?}", r#"us\u{202B}e\u{202A}r"#);
+ println!("{:?}", b"us\u{202B}e\u{202A}r");
+ //~^ ERROR unicode escape in byte string
+ //~| ERROR unicode escape in byte string
+ println!("{:?}", br##"us\u{202B}e\u{202A}r"##);
+
+ println!("{:?}", "/* } if isAdmin begin admins only ");
+ //~^ ERROR unicode codepoint changing visible direction of text present in literal
+
+ println!("{:?}", r##"/* } if isAdmin begin admins only "##);
+ //~^ ERROR unicode codepoint changing visible direction of text present in literal
+ println!("{:?}", b"/* } if isAdmin begin admins only ");
+ //~^ ERROR non-ASCII character in byte constant
+ //~| ERROR non-ASCII character in byte constant
+ //~| ERROR non-ASCII character in byte constant
+ //~| ERROR non-ASCII character in byte constant
+ println!("{:?}", br##"/* } if isAdmin begin admins only "##);
+ //~^ ERROR raw byte string must be ASCII
+ //~| ERROR raw byte string must be ASCII
+ //~| ERROR raw byte string must be ASCII
+ //~| ERROR raw byte string must be ASCII
+ println!("{:?}", '');
+ //~^ ERROR unicode codepoint changing visible direction of text present in literal
+}
+
+//"/* } if isAdmin begin admins only */"
+//~^ ERROR unicode codepoint changing visible direction of text present in comment
+
+/** ''); */fn foo() {}
+//~^ ERROR unicode codepoint changing visible direction of text present in doc comment
+
+/**
+ *
+ * ''); */fn bar() {}
+//~^^^ ERROR unicode codepoint changing visible direction of text present in doc comment
--- /dev/null
+error: unicode escape in byte string
+ --> $DIR/unicode-control-codepoints.rs:6:26
+ |
+LL | println!("{:?}", b"us\u{202B}e\u{202A}r");
+ | ^^^^^^^^ unicode escape in byte string
+ |
+ = help: unicode escape sequences cannot be used as a byte or in a byte string
+
+error: unicode escape in byte string
+ --> $DIR/unicode-control-codepoints.rs:6:35
+ |
+LL | println!("{:?}", b"us\u{202B}e\u{202A}r");
+ | ^^^^^^^^ unicode escape in byte string
+ |
+ = help: unicode escape sequences cannot be used as a byte or in a byte string
+
+error: non-ASCII character in byte constant
+ --> $DIR/unicode-control-codepoints.rs:16:26
+ |
+LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
+ | ^ byte constant must be ASCII but is '\u{202e}'
+ |
+help: if you meant to use the UTF-8 encoding of '\u{202e}', use \xHH escapes
+ |
+LL | println!("{:?}", b"/*\xE2\x80\xAE } if isAdmin begin admins only ");
+ | ~~~~~~~~~~~~
+
+error: non-ASCII character in byte constant
+ --> $DIR/unicode-control-codepoints.rs:16:30
+ |
+LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
+ | ^ byte constant must be ASCII but is '\u{2066}'
+ |
+help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes
+ |
+LL | println!("{:?}", b"/* } \xE2\x81\xA6if isAdmin begin admins only ");
+ | ~~~~~~~~~~~~
+
+error: non-ASCII character in byte constant
+ --> $DIR/unicode-control-codepoints.rs:16:41
+ |
+LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
+ | ^ byte constant must be ASCII but is '\u{2069}'
+ |
+help: if you meant to use the UTF-8 encoding of '\u{2069}', use \xHH escapes
+ |
+LL | println!("{:?}", b"/* } if isAdmin\xE2\x81\xA9 begin admins only ");
+ | ~~~~~~~~~~~~
+
+error: non-ASCII character in byte constant
+ --> $DIR/unicode-control-codepoints.rs:16:43
+ |
+LL | println!("{:?}", b"/* } if isAdmin begin admins only ");
+ | ^ byte constant must be ASCII but is '\u{2066}'
+ |
+help: if you meant to use the UTF-8 encoding of '\u{2066}', use \xHH escapes
+ |
+LL | println!("{:?}", b"/* } if isAdmin \xE2\x81\xA6 begin admins only ");
+ | ~~~~~~~~~~~~
+
+error: raw byte string must be ASCII
+ --> $DIR/unicode-control-codepoints.rs:21:29
+ |
+LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);
+ | ^ must be ASCII but is '\u{202e}'
+
+error: raw byte string must be ASCII
+ --> $DIR/unicode-control-codepoints.rs:21:33
+ |
+LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);
+ | ^ must be ASCII but is '\u{2066}'
+
+error: raw byte string must be ASCII
+ --> $DIR/unicode-control-codepoints.rs:21:44
+ |
+LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);
+ | ^ must be ASCII but is '\u{2069}'
+
+error: raw byte string must be ASCII
+ --> $DIR/unicode-control-codepoints.rs:21:46
+ |
+LL | println!("{:?}", br##"/* } if isAdmin begin admins only "##);
+ | ^ must be ASCII but is '\u{2066}'
+
+error: unicode codepoint changing visible direction of text present in comment
+ --> $DIR/unicode-control-codepoints.rs:2:5
+ |
+LL | // if access_level != "user" { // Check if admin
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^
+ | | ||
+ | | |'\u{202a}'
+ | | '\u{202b}'
+ | this comment contains invisible unicode text flow control codepoints
+ |
+ = note: `#[deny(text_direction_codepoint_in_comment)]` on by default
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = help: if their presence wasn't intentional, you can remove them
+
+error: unicode codepoint changing visible direction of text present in comment
+ --> $DIR/unicode-control-codepoints.rs:30:1
+ |
+LL | //"/* } if isAdmin begin admins only */"
+ | ^^^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^
+ | | | | ||
+ | | | | |'\u{2066}'
+ | | | | '\u{2069}'
+ | | | '\u{2066}'
+ | | '\u{202e}'
+ | this comment contains invisible unicode text flow control codepoints
+ |
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = help: if their presence wasn't intentional, you can remove them
+
+error: unicode codepoint changing visible direction of text present in literal
+ --> $DIR/unicode-control-codepoints.rs:11:22
+ |
+LL | println!("{:?}", "/* } if isAdmin begin admins only ");
+ | ^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^
+ | | | | ||
+ | | | | |'\u{2066}'
+ | | | | '\u{2069}'
+ | | | '\u{2066}'
+ | | '\u{202e}'
+ | this literal contains invisible unicode text flow control codepoints
+ |
+ = note: `#[deny(text_direction_codepoint_in_literal)]` on by default
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = help: if their presence wasn't intentional, you can remove them
+help: if you want to keep them but make them visible in your source code, you can escape them
+ |
+LL | println!("{:?}", "/*\u{202e} } \u{2066}if isAdmin\u{2069} \u{2066} begin admins only ");
+ | ~~~~~~~~ ~~~~~~~~ ~~~~~~~~ ~~~~~~~~
+
+error: unicode codepoint changing visible direction of text present in literal
+ --> $DIR/unicode-control-codepoints.rs:14:22
+ |
+LL | println!("{:?}", r##"/* } if isAdmin begin admins only "##);
+ | ^^^^^^-^^-^^^^^^^^^--^^^^^^^^^^^^^^^^^^^^^
+ | | | | ||
+ | | | | |'\u{2066}'
+ | | | | '\u{2069}'
+ | | | '\u{2066}'
+ | | '\u{202e}'
+ | this literal contains invisible unicode text flow control codepoints
+ |
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = help: if their presence wasn't intentional, you can remove them
+help: if you want to keep them but make them visible in your source code, you can escape them
+ |
+LL | println!("{:?}", r##"/*\u{202e} } \u{2066}if isAdmin\u{2069} \u{2066} begin admins only "##);
+ | ~~~~~~~~ ~~~~~~~~ ~~~~~~~~ ~~~~~~~~
+
+error: unicode codepoint changing visible direction of text present in literal
+ --> $DIR/unicode-control-codepoints.rs:26:22
+ |
+LL | println!("{:?}", '');
+ | ^-
+ | ||
+ | |'\u{202e}'
+ | this literal contains an invisible unicode text flow control codepoint
+ |
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = help: if their presence wasn't intentional, you can remove them
+help: if you want to keep them but make them visible in your source code, you can escape them
+ |
+LL | println!("{:?}", '\u{202e}');
+ | ~~~~~~~~
+
+error: unicode codepoint changing visible direction of text present in doc comment
+ --> $DIR/unicode-control-codepoints.rs:33:1
+ |
+LL | /** ''); */fn foo() {}
+ | ^^^^^^^^^^^^ this doc comment contains an invisible unicode text flow control codepoint
+ |
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = note: if their presence wasn't intentional, you can remove them
+ = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}'
+
+error: unicode codepoint changing visible direction of text present in doc comment
+ --> $DIR/unicode-control-codepoints.rs:36:1
+ |
+LL | / /**
+LL | | *
+LL | | * ''); */fn bar() {}
+ | |___________^ this doc comment contains an invisible unicode text flow control codepoint
+ |
+ = note: these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+ = note: if their presence wasn't intentional, you can remove them
+ = note: if you want to keep them but make them visible in your source code, you can escape them: '\u{202e}'
+
+error: aborting due to 17 previous errors
+
--- /dev/null
+// run-pass
+// Destructuring struct variants would ICE where regular structs wouldn't
+
+enum Foo {
+ VBar { num: isize }
+}
+
+struct SBar { num: isize }
+
+pub fn main() {
+ let vbar = Foo::VBar { num: 1 };
+ let Foo::VBar { num } = vbar;
+ assert_eq!(num, 1);
+
+ let sbar = SBar { num: 2 };
+ let SBar { num } = sbar;
+ assert_eq!(num, 2);
+}
--- /dev/null
+// run-pass
+
+fn main() {
+ let mut x: &[_] = &[1, 2, 3, 4];
+
+ let mut result = vec![];
+ loop {
+ x = match *x {
+ [1, n, 3, ref rest @ ..] => {
+ result.push(n);
+ rest
+ }
+ [n, ref rest @ ..] => {
+ result.push(n);
+ rest
+ }
+ [] =>
+ break
+ }
+ }
+ assert_eq!(result, [2, 4]);
+}
--- /dev/null
+struct Binder(i32, i32, i32);
+
+fn main() {
+ let x = Binder(1, 2, 3);
+ match x {
+ Binder(_a, _x @ ..) => {}
+ _ => {}
+ }
+}
+//~^^^^ ERROR `_x @` is not allowed in a tuple struct
+//~| ERROR: `..` patterns are not allowed here
+//~| ERROR: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
--- /dev/null
+error: `_x @` is not allowed in a tuple struct
+ --> $DIR/issue-72574-2.rs:6:20
+ |
+LL | Binder(_a, _x @ ..) => {}
+ | ^^^^^^^ this is only allowed in slice patterns
+ |
+ = help: remove this and bind each tuple field independently
+help: if you don't need to use the contents of _x, discard the tuple's remaining fields
+ |
+LL | Binder(_a, ..) => {}
+ | ~~
+
+error: `..` patterns are not allowed here
+ --> $DIR/issue-72574-2.rs:6:25
+ |
+LL | Binder(_a, _x @ ..) => {}
+ | ^^
+ |
+ = note: only allowed in tuple, tuple struct, and slice patterns
+
+error[E0023]: this pattern has 2 fields, but the corresponding tuple struct has 3 fields
+ --> $DIR/issue-72574-2.rs:6:16
+ |
+LL | struct Binder(i32, i32, i32);
+ | --- --- --- tuple struct has 3 fields
+...
+LL | Binder(_a, _x @ ..) => {}
+ | ^^ ^^^^^^^ expected 3 fields, found 2
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | Binder(_a, _x @ .., _) => {}
+ | +++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0023`.
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+
+enum E {
+ Foo{f: isize},
+ Bar,
+}
+
+pub fn main() {
+ let e = E::Foo{f: 0};
+ match e {
+ E::Foo{f: 1} => panic!(),
+ E::Foo{..} => (),
+ _ => panic!(),
+ }
+}
--- /dev/null
+// run-pass
+#![allow(dead_code)]
+
+enum E {
+ Foo{f: isize, b: bool},
+ Bar,
+}
+
+pub fn main() {
+ let e = E::Foo{f: 0, b: false};
+ match e {
+ E::Foo{f: 1, b: true} => panic!(),
+ E::Foo{b: false, f: 0} => (),
+ _ => panic!(),
+ }
+}
// aux-crate:priv:priv_dep=priv_dep.rs
// aux-build:pub_dep.rs
+// compile-flags: -Zunstable-options
#![deny(exported_private_dependencies)]
// This crate is a private dependency
error: type `OtherType` from private dependency 'priv_dep' in public interface
- --> $DIR/pub-priv1.rs:20:5
+ --> $DIR/pub-priv1.rs:21:5
|
LL | pub field: OtherType,
| ^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/pub-priv1.rs:3:9
+ --> $DIR/pub-priv1.rs:4:9
|
LL | #![deny(exported_private_dependencies)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: type `OtherType` from private dependency 'priv_dep' in public interface
- --> $DIR/pub-priv1.rs:27:5
+ --> $DIR/pub-priv1.rs:28:5
|
LL | pub fn pub_fn(param: OtherType) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: trait `OtherTrait` from private dependency 'priv_dep' in public interface
- --> $DIR/pub-priv1.rs:34:5
+ --> $DIR/pub-priv1.rs:35:5
|
LL | type Foo: OtherTrait;
| ^^^^^^^^^^^^^^^^^^^^^
}
use deny as allow;
-#[allow(unused)] //~ ERROR `allow` is ambiguous (built-in attribute vs any other name)
+#[allow(unused)] //~ ERROR `allow` is ambiguous
fn builtin_renamed() {}
LL | NonExistent;
| ^^^^^^^^^^^ not found in this scope
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:9:3
|
LL | #[repr(C)]
| ^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `repr` could refer to a built-in attribute
note: `repr` could also refer to the attribute macro imported here
--> $DIR/ambiguous-builtin-attrs.rs:6:5
| ^^^^^^^^^^^^^^^^
= help: use `crate::repr` to refer to this attribute macro unambiguously
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:11:19
|
LL | #[cfg_attr(all(), repr(C))]
| ^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `repr` could refer to a built-in attribute
note: `repr` could also refer to the attribute macro imported here
--> $DIR/ambiguous-builtin-attrs.rs:6:5
| ^^^^^^^^^^^^^^^^
= help: use `crate::repr` to refer to this attribute macro unambiguously
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:20:34
|
LL | fn non_macro_expanded_location<#[repr(C)] T>() {
| ^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `repr` could refer to a built-in attribute
note: `repr` could also refer to the attribute macro imported here
--> $DIR/ambiguous-builtin-attrs.rs:6:5
| ^^^^^^^^^^^^^^^^
= help: use `crate::repr` to refer to this attribute macro unambiguously
-error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `repr` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:24:11
|
LL | #[repr(C)]
| ^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `repr` could refer to a built-in attribute
note: `repr` could also refer to the attribute macro imported here
--> $DIR/ambiguous-builtin-attrs.rs:6:5
| ^^^^^^^^^^^^^^^^
= help: use `crate::repr` to refer to this attribute macro unambiguously
-error[E0659]: `allow` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `allow` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:38:3
|
LL | #[allow(unused)]
| ^^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `allow` could refer to a built-in attribute
note: `allow` could also refer to the built-in attribute imported here
--> $DIR/ambiguous-builtin-attrs.rs:37:5
| ^^^^^^^^^^^^^
= help: use `crate::allow` to refer to this built-in attribute unambiguously
-error[E0659]: `feature` is ambiguous (built-in attribute vs any other name)
+error[E0659]: `feature` is ambiguous
--> $DIR/ambiguous-builtin-attrs.rs:3:4
|
LL | #![feature(decl_macro)]
| ^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a builtin attribute
= note: `feature` could refer to a built-in attribute
note: `feature` could also refer to the attribute macro imported here
--> $DIR/ambiguous-builtin-attrs.rs:6:5
+// ignore-tidy-linelength
+
use proc_macro::Literal;
pub fn test() {
fn test_display_literal() {
assert_eq!(Literal::isize_unsuffixed(-10).to_string(), "-10");
assert_eq!(Literal::isize_suffixed(-10).to_string(), "-10isize");
+ assert_eq!(Literal::f32_unsuffixed(-10.0).to_string(), "-10.0");
+ assert_eq!(Literal::f32_suffixed(-10.0).to_string(), "-10f32");
+ assert_eq!(Literal::f64_unsuffixed(-10.0).to_string(), "-10.0");
+ assert_eq!(Literal::f64_suffixed(-10.0).to_string(), "-10f64");
+ assert_eq!(
+ Literal::f64_unsuffixed(1e100).to_string(),
+ "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0",
+ );
}
fn test_parse_literal() {
crate::empty_helper
= note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info)
-error[E0659]: `empty_helper` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `empty_helper` is ambiguous
--> $DIR/derive-helper-shadowing.rs:26:13
|
LL | use empty_helper;
| ^^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `empty_helper` could refer to the derive helper attribute defined here
--> $DIR/derive-helper-shadowing.rs:22:10
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use `crate::empty_helper` to refer to this attribute macro unambiguously
-error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `empty_helper` is ambiguous
--> $DIR/derive-helper-shadowing.rs:19:3
|
LL | #[empty_helper]
| ^^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `empty_helper` could refer to the derive helper attribute defined here
--> $DIR/derive-helper-shadowing.rs:22:10
|
-error[E0659]: `empty_helper` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `empty_helper` is ambiguous
--> $DIR/helper-attr-blocked-by-import-ambig.rs:7:3
|
LL | #[empty_helper]
| ^^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `empty_helper` could refer to the derive helper attribute defined here
--> $DIR/helper-attr-blocked-by-import-ambig.rs:10:10
|
-error[E0659]: `identity_attr` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
+error[E0659]: `identity_attr` is ambiguous
--> $DIR/issue-41211.rs:11:4
|
LL | #![identity_attr]
| ^^^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution
note: `identity_attr` could refer to the attribute macro imported here
--> $DIR/issue-41211.rs:14:5
|
crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it")
crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site")
crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
crate0::{{expn2}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "outer")
crate0::{{expn3}}: parent: crate0::{{expn2}}, call_site_ctxt: #4, def_site_ctxt: #4, kind: Macro(Bang, "inner")
crate0::{{expn4}}: parent: crate0::{{expn3}}, call_site_ctxt: #6, def_site_ctxt: #0, kind: Macro(Bang, "print_bang")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
+crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Attr, "derive")
crate1::{{expnNNN}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "include")
crate2::{{expn1}}: parent: crate0::{{expn0}}, call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
LL | #[C]
| ^ help: a derive helper attribute with a similar name exists: `B`
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
--> $DIR/proc-macro-attributes.rs:6:3
|
LL | #[B]
| ^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `B` could refer to the derive helper attribute defined here
--> $DIR/proc-macro-attributes.rs:19:10
|
LL | #[macro_use]
| ^^^^^^^^^^^^
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
--> $DIR/proc-macro-attributes.rs:10:3
|
LL | #[B(D)]
| ^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `B` could refer to the derive helper attribute defined here
--> $DIR/proc-macro-attributes.rs:19:10
|
LL | #[macro_use]
| ^^^^^^^^^^^^
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
--> $DIR/proc-macro-attributes.rs:13:3
|
LL | #[B(E = "foo")]
| ^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `B` could refer to the derive helper attribute defined here
--> $DIR/proc-macro-attributes.rs:19:10
|
LL | #[macro_use]
| ^^^^^^^^^^^^
-error[E0659]: `B` is ambiguous (derive helper attribute vs any other name)
+error[E0659]: `B` is ambiguous
--> $DIR/proc-macro-attributes.rs:16:3
|
LL | #[B(arbitrary tokens)]
| ^ ambiguous name
|
+ = note: ambiguous because of a name conflict with a derive helper attribute
note: `B` could refer to the derive helper attribute defined here
--> $DIR/proc-macro-attributes.rs:19:10
|
--- /dev/null
+// run-pass
+#![allow(unused_mut)]
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+use std::env;
+use std::io::prelude::*;
+use std::io;
+use std::process::{Command, Stdio};
+
+fn main() {
+ let args: Vec<String> = env::args().collect();
+ if args.len() > 1 && args[1] == "child" {
+ return child()
+ }
+
+ test();
+}
+
+fn child() {
+ writeln!(&mut io::stdout(), "foo").unwrap();
+ writeln!(&mut io::stderr(), "bar").unwrap();
+ let mut stdin = io::stdin();
+ let mut s = String::new();
+ stdin.lock().read_line(&mut s).unwrap();
+ assert_eq!(s.len(), 0);
+}
+
+fn test() {
+ let args: Vec<String> = env::args().collect();
+ let mut p = Command::new(&args[0]).arg("child")
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
+ .spawn().unwrap();
+ assert!(p.wait().unwrap().success());
+}
--- /dev/null
+// run-pass
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+use std::process::Command;
+use std::env;
+
+fn main() {
+ let len = env::args().len();
+
+ if len == 1 {
+ test();
+ } else {
+ assert_eq!(len, 3);
+ }
+}
+
+fn test() {
+ let status = Command::new(&env::current_exe().unwrap())
+ .arg("foo").arg("")
+ .status().unwrap();
+ assert!(status.success());
+}
--- /dev/null
+// run-pass
+#![allow(stable_features)]
+
+// ignore-emscripten no processes
+// ignore-sgx no processes
+
+#![feature(os)]
+
+#[cfg(unix)]
+fn main() {
+ use std::process::Command;
+ use std::env;
+ use std::os::unix::prelude::*;
+ use std::ffi::OsStr;
+
+ if env::args().len() == 1 {
+ assert!(Command::new(&env::current_exe().unwrap())
+ .arg(<OsStr as OsStrExt>::from_bytes(b"\xff"))
+ .status().unwrap().success())
+ }
+}
+
+#[cfg(windows)]
+fn main() {}
--- /dev/null
+// run-pass
+// ignore-emscripten no processes
+// ignore-sgx no processes
+// ignore-windows
+
+use std::env;
+use std::process::Command;
+
+pub fn main() {
+ let args: Vec<String> = env::args().collect();
+ if args.len() >= 2 && args[1] == "signal" {
+ // Raise a segfault.
+ unsafe { *(1 as *mut isize) = 0; }
+ } else {
+ let status = Command::new(&args[0]).arg("signal").status().unwrap();
+ assert!(status.code().is_none());
+ }
+}
fn a() {
// the cast is unreachable:
let x = {return} as !; //~ ERROR unreachable
+ //~| ERROR non-primitive cast
}
fn main() { }
LL | #![deny(unreachable_code)]
| ^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error[E0605]: non-primitive cast: `()` as `!`
+ --> $DIR/expr_cast.rs:9:13
+ |
+LL | let x = {return} as !;
+ | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0605`.
--- /dev/null
+// check-pass
+#![allow(dead_code)]
+// Test that the requirement (in `Bar`) that `T::Bar : 'static` does
+// not wind up propagating to `T`.
+
+// pretty-expanded FIXME #23616
+
+pub trait Foo {
+ type Bar;
+
+ fn foo(&self) -> Self;
+}
+
+pub struct Static<T:'static>(T);
+
+struct Bar<T:Foo>
+ where T::Bar : 'static
+{
+ x: Static<Option<T::Bar>>
+}
+
+fn main() { }
--- /dev/null
+// run-pass
+
+pub trait Foo<T> {
+ fn foo(self) -> T;
+}
+
+impl<'a, T> Foo<T> for &'a str where &'a str: Into<T> {
+ fn foo(self) -> T {
+ panic!();
+ }
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+pub struct Bar<T> {
+ items: Vec<&'static str>,
+ inner: T,
+}
+
+pub trait IntoBar<T> {
+ fn into_bar(self) -> Bar<T>;
+}
+
+impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> {
+ fn into_bar(self) -> Bar<T> {
+ Bar {
+ items: Vec::new(),
+ inner: self.into(),
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+pub struct Item {
+ _inner: &'static str,
+}
+
+pub struct Bar<T> {
+ items: Vec<Item>,
+ inner: T,
+}
+
+pub trait IntoBar<T> {
+ fn into_bar(self) -> Bar<T>;
+}
+
+impl<'a, T> IntoBar<T> for &'a str where &'a str: Into<T> {
+ fn into_bar(self) -> Bar<T> {
+ Bar {
+ items: Vec::new(),
+ inner: self.into(),
+ }
+ }
+}
+
+fn main() {}
+++ /dev/null
-// build-fail
-
-#![feature(lang_items, no_core)]
-#![no_core]
-
-#[lang="copy"] pub trait Copy { }
-#[lang="sized"] pub trait Sized { }
-
-// error-pattern:requires `start` lang_item
-
-fn main() {}
+++ /dev/null
-error: requires `start` lang_item
-
-error: aborting due to previous error
-
--- /dev/null
+// edition:2015
+
+mod inner {
+ fn global_inner(_: ::nonexistant::Foo) {
+ //~^ ERROR failed to resolve: maybe a missing crate `nonexistant`?
+ }
+ fn crate_inner(_: crate::nonexistant::Foo) {
+ //~^ ERROR failed to resolve: maybe a missing crate `nonexistant`?
+ }
+
+ fn bare_global(_: ::nonexistant) {
+ //~^ ERROR cannot find type `nonexistant` in the crate root
+ }
+ fn bare_crate(_: crate::nonexistant) {
+ //~^ ERROR cannot find type `nonexistant` in the crate root
+ }
+}
+
+fn main() {
+
+}
--- /dev/null
+error[E0433]: failed to resolve: maybe a missing crate `nonexistant`?
+ --> $DIR/editions-crate-root-2015.rs:4:26
+ |
+LL | fn global_inner(_: ::nonexistant::Foo) {
+ | ^^^^^^^^^^^ maybe a missing crate `nonexistant`?
+
+error[E0433]: failed to resolve: maybe a missing crate `nonexistant`?
+ --> $DIR/editions-crate-root-2015.rs:7:30
+ |
+LL | fn crate_inner(_: crate::nonexistant::Foo) {
+ | ^^^^^^^^^^^ maybe a missing crate `nonexistant`?
+
+error[E0412]: cannot find type `nonexistant` in the crate root
+ --> $DIR/editions-crate-root-2015.rs:11:25
+ |
+LL | fn bare_global(_: ::nonexistant) {
+ | ^^^^^^^^^^^ not found in the crate root
+
+error[E0412]: cannot find type `nonexistant` in the crate root
+ --> $DIR/editions-crate-root-2015.rs:14:29
+ |
+LL | fn bare_crate(_: crate::nonexistant) {
+ | ^^^^^^^^^^^ not found in the crate root
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0412, E0433.
+For more information about an error, try `rustc --explain E0412`.
--- /dev/null
+trait Trait {
+ fn outer(&self) {
+ fn inner(_: &Self) {
+ //~^ ERROR can't use generic parameters from outer function
+ }
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-12796.rs:3:22
+ |
+LL | fn inner(_: &Self) {
+ | ^^^^
+ | |
+ | use of generic parameter from outer function
+ | can't use `Self` here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0401`.
--- /dev/null
+static foo: i32 = 0;
+
+fn bar(foo: i32) {}
+//~^ ERROR function parameters cannot shadow statics
+//~| cannot be named the same as a static
+
+mod submod {
+ pub static answer: i32 = 42;
+}
+
+use self::submod::answer;
+
+fn question(answer: i32) {}
+//~^ ERROR function parameters cannot shadow statics
+//~| cannot be named the same as a static
+fn main() {
+}
--- /dev/null
+error[E0530]: function parameters cannot shadow statics
+ --> $DIR/issue-23716.rs:3:8
+ |
+LL | static foo: i32 = 0;
+ | -------------------- the static `foo` is defined here
+LL |
+LL | fn bar(foo: i32) {}
+ | ^^^ cannot be named the same as a static
+
+error[E0530]: function parameters cannot shadow statics
+ --> $DIR/issue-23716.rs:13:13
+ |
+LL | use self::submod::answer;
+ | -------------------- the static `answer` is imported here
+LL |
+LL | fn question(answer: i32) {}
+ | ^^^^^^ cannot be named the same as a static
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0530`.
--- /dev/null
+fn siphash<T>() {
+
+ trait U {
+ fn g(&self, x: T) -> T; //~ ERROR can't use generic parameters from outer function
+ //~^ ERROR can't use generic parameters from outer function
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-3021-c.rs:4:24
+ |
+LL | fn siphash<T>() {
+ | - type parameter from outer function
+...
+LL | fn g(&self, x: T) -> T;
+ | - ^ use of generic parameter from outer function
+ | |
+ | help: try using a local generic parameter instead: `g<T>`
+
+error[E0401]: can't use generic parameters from outer function
+ --> $DIR/issue-3021-c.rs:4:30
+ |
+LL | fn siphash<T>() {
+ | - type parameter from outer function
+...
+LL | fn g(&self, x: T) -> T;
+ | - ^ use of generic parameter from outer function
+ | |
+ | help: try using a local generic parameter instead: `g<T>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0401`.
--- /dev/null
+trait SipHash {
+ fn reset(&self);
+}
+
+fn siphash(k0 : u64) {
+ struct SipState {
+ v0: u64,
+ }
+
+ impl SipHash for SipState {
+ fn reset(&self) {
+ self.v0 = k0 ^ 0x736f6d6570736575; //~ ERROR can't capture dynamic environment
+ }
+ }
+ panic!();
+}
+
+fn main() {}
--- /dev/null
+error[E0434]: can't capture dynamic environment in a fn item
+ --> $DIR/issue-3021.rs:12:22
+ |
+LL | self.v0 = k0 ^ 0x736f6d6570736575;
+ | ^^
+ |
+ = help: use the `|| { ... }` closure form instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0434`.
--- /dev/null
+// Checks lexical scopes cannot see through normal module boundaries
+
+fn f() {
+ fn g() {}
+ mod foo {
+ fn h() {
+ g(); //~ ERROR cannot find function `g` in this scope
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0425]: cannot find function `g` in this scope
+ --> $DIR/issue-31845.rs:7:12
+ |
+LL | g();
+ | ^ not found in this scope
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
--- /dev/null
+trait B <A> {
+ fn a() -> A {
+ this.a //~ ERROR cannot find value `this` in this scope
+ }
+ fn b(x: i32) {
+ this.b(x); //~ ERROR cannot find value `this` in this scope
+ }
+ fn c() {
+ let _ = || this.a; //~ ERROR cannot find value `this` in this scope
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0425]: cannot find value `this` in this scope
+ --> $DIR/issue-5099.rs:3:9
+ |
+LL | this.a
+ | ^^^^ not found in this scope
+ |
+help: you might have meant to use `self` here instead
+ |
+LL | self.a
+ | ~~~~
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+ |
+LL | fn a(&self) -> A {
+ | +++++
+
+error[E0425]: cannot find value `this` in this scope
+ --> $DIR/issue-5099.rs:6:9
+ |
+LL | this.b(x);
+ | ^^^^ not found in this scope
+ |
+help: you might have meant to use `self` here instead
+ |
+LL | self.b(x);
+ | ~~~~
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+ |
+LL | fn b(&self, x: i32) {
+ | ++++++
+
+error[E0425]: cannot find value `this` in this scope
+ --> $DIR/issue-5099.rs:9:20
+ |
+LL | let _ = || this.a;
+ | ^^^^ not found in this scope
+ |
+help: you might have meant to use `self` here instead
+ |
+LL | let _ = || self.a;
+ | ~~~~
+help: if you meant to use `self`, you are also missing a `self` receiver argument
+ |
+LL | fn c(&self) {
+ | +++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
--- /dev/null
+mod list {
+ pub use self::List::Cons;
+
+ pub enum List<T> {
+ Cons(T, Box<List<T>>),
+ }
+}
+
+mod alias {
+ use crate::list::List;
+
+ pub type Foo = List<String>;
+}
+
+fn foo(l: crate::alias::Foo) {
+ match l {
+ Cons(..) => {} //~ ERROR: cannot find tuple struct or tuple variant `Cons` in this scope
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0531]: cannot find tuple struct or tuple variant `Cons` in this scope
+ --> $DIR/issue-90113.rs:17:9
+ |
+LL | Cons(..) => {}
+ | ^^^^ not found in this scope
+ |
+help: consider importing this tuple variant
+ |
+LL | use list::List::Cons;
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0531`.
--- /dev/null
+// Matching against NaN should result in a warning
+
+#![allow(unused)]
+#![deny(illegal_floating_point_literal_pattern)]
+
+const NAN: f64 = f64::NAN;
+
+fn main() {
+ let x = NAN;
+ match x {
+ NAN => {}, //~ ERROR floating-point types cannot be used
+ //~| WARN this was previously accepted by the compiler but is being phased out
+ _ => {},
+ };
+
+ match [x, 1.0] {
+ [NAN, _] => {}, //~ ERROR floating-point types cannot be used
+ //~| WARN this was previously accepted by the compiler but is being phased out
+ _ => {},
+ };
+}
--- /dev/null
+error: floating-point types cannot be used in patterns
+ --> $DIR/issue-6804.rs:11:9
+ |
+LL | NAN => {},
+ | ^^^
+ |
+note: the lint level is defined here
+ --> $DIR/issue-6804.rs:4:9
+ |
+LL | #![deny(illegal_floating_point_literal_pattern)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = 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>
+
+error: floating-point types cannot be used in patterns
+ --> $DIR/issue-6804.rs:17:10
+ |
+LL | [NAN, _] => {},
+ | ^^^
+ |
+ = 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>
+
+error: aborting due to 2 previous errors
+
error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
--> $DIR/const-drop-fail.rs:49:5
|
-LL | const _: () = check($exp);
- | ----- required by a bound introduced by this call
-...
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
|
error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
--> $DIR/const-drop-fail.rs:49:5
|
-LL | const _: () = check($exp);
- | ----- required by a bound introduced by this call
-...
LL | ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
|
println!("{:#?}", output);
let stderr = std::str::from_utf8(&output.stderr);
assert!(stderr.map(|v| {
- v.ends_with("drop of the panic payload panicked")
+ v.ends_with("fatal runtime error: drop of the panic payload panicked\n")
}).unwrap_or(false));
}
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/ambiguity-macros-nested.rs:8:13
|
LL | pub use std::io;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `std` could refer to a built-in crate
= help: use `::std` to refer to this crate unambiguously
note: `std` could also refer to the module defined here
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/ambiguity-macros.rs:7:5
|
LL | use std::io;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `std` could refer to a built-in crate
= help: use `::std` to refer to this crate unambiguously
note: `std` could also refer to the module defined here
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/ambiguity-nested.rs:8:13
|
LL | pub use std::io;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `std` could refer to a built-in crate
= help: use `::std` to refer to this crate unambiguously
note: `std` could also refer to the module defined here
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/ambiguity.rs:5:5
|
LL | use std::io;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `std` could refer to a built-in crate
= help: use `::std` to refer to this crate unambiguously
note: `std` could also refer to the module defined here
-error[E0659]: `sub` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `sub` is ambiguous
--> $DIR/block-scoped-shadow-nested.rs:16:13
|
LL | use sub::bar;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `sub` could refer to the module imported here
--> $DIR/block-scoped-shadow-nested.rs:14:9
|
-error[E0659]: `Foo` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `Foo` is ambiguous
--> $DIR/block-scoped-shadow.rs:11:9
|
LL | use Foo::*;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `Foo` could refer to the enum defined here
--> $DIR/block-scoped-shadow.rs:10:5
|
| ^^^^^^^^^^^
= help: use `crate::Foo` to refer to this enum unambiguously
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/block-scoped-shadow.rs:18:9
|
LL | use std as foo;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `std` could refer to the enum defined here
--> $DIR/block-scoped-shadow.rs:17:5
|
| ^^^^^^^^^^^
= help: use `crate::std` to refer to this struct unambiguously
-error[E0659]: `std` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `std` is ambiguous
--> $DIR/block-scoped-shadow.rs:18:9
|
LL | use std as foo;
| ^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `std` could refer to the function defined here
--> $DIR/block-scoped-shadow.rs:16:5
|
-error[E0659]: `issue_56596` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `issue_56596` is ambiguous
--> $DIR/issue-56596.rs:12:5
|
LL | use issue_56596;
| ^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
= note: `issue_56596` could refer to a crate passed with `--extern`
= help: use `::issue_56596` to refer to this crate unambiguously
note: `issue_56596` could also refer to the module imported here
LL | pub use legacy_macro as _;
| ^^^^^^^^^^^^^^^^^
-error[E0659]: `legacy_macro` is ambiguous (name vs any other name during import resolution)
+error[E0659]: `legacy_macro` is ambiguous
--> $DIR/macro-rules.rs:31:13
|
LL | use legacy_macro as _;
| ^^^^^^^^^^^^ ambiguous name
|
+ = note: ambiguous because of multiple potential import sources
note: `legacy_macro` could refer to the macro defined here
--> $DIR/macro-rules.rs:28:9
|
}
fn main() {
- io::stdout();
- self::std::io::stdout();
- foo::my_std::io::stdout();
- bar::std::io::stdout();
+ let _ = io::stdout();
+ let _ = self::std::io::stdout();
+ let _ = foo::my_std::io::stdout();
+ let _ = bar::std::io::stdout();
}
| the method is available for `Rc<u8>` here
|
= help: items from traits can only be used if the trait is in scope
+ = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
help: consider wrapping the receiver expression with the appropriate type
|
LL | let _: u32 = Box::new(3u8).try_into().unwrap();
// check-pass
// edition:2021
-// compile-flags: -Zunstable-options
fn main() {
let _: u16 = 123i32.try_into().unwrap();
// check-pass
// run-rustfix
-// compile-flags: -Z unstable-options --edition 2018
+// edition:2018
#![warn(rust_2021_prefixes_incompatible_syntax)]
// check-pass
// run-rustfix
-// compile-flags: -Z unstable-options --edition 2018
+// edition:2018
#![warn(rust_2021_prefixes_incompatible_syntax)]
--- /dev/null
+struct A<T>(T);
+
+impl A<&'static u8> {
+ fn f() {
+ let x = 0;
+ Self(&x);
+ //~^ ERROR `x` does not live long enough
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0597]: `x` does not live long enough
+ --> $DIR/issue-61882-2.rs:6:14
+ |
+LL | Self(&x);
+ | ^^
+ | |
+ | borrowed value does not live long enough
+ | this usage requires that `x` is borrowed for `'static`
+LL |
+LL | }
+ | - `x` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+struct A<T>(T);
+
+impl A<bool> {
+ const B: A<u8> = Self(0);
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-61882.rs:4:27
+ |
+LL | const B: A<u8> = Self(0);
+ | ^ expected `bool`, found integer
+
+error[E0308]: mismatched types
+ --> $DIR/issue-61882.rs:4:22
+ |
+LL | const B: A<u8> = Self(0);
+ | ^^^^^^^ expected `u8`, found `bool`
+ |
+ = note: expected struct `A<u8>`
+ found struct `A<bool>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// run-pass
-// ignore-emscripten no processes
-// ignore-sgx no processes
-// ignore-windows
-
-use std::env;
-use std::process::Command;
-
-pub fn main() {
- let args: Vec<String> = env::args().collect();
- if args.len() >= 2 && args[1] == "signal" {
- // Raise a segfault.
- unsafe { *(1 as *mut isize) = 0; }
- } else {
- let status = Command::new(&args[0]).arg("signal").status().unwrap();
- assert!(status.code().is_none());
- }
-}
--- /dev/null
+// run-pass
+
+#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
+
+trait Specializable { type Output; }
+
+impl<T> Specializable for T {
+ default type Output = u16;
+}
+
+fn main() {
+ unsafe {
+ std::mem::transmute::<u16, <() as Specializable>::Output>(0);
+ }
+}
--- /dev/null
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/transmute-specialization.rs:3:12
+ |
+LL | #![feature(specialization)]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+ = help: consider using `min_specialization` instead, which is more stable and complete
+
+warning: 1 warning emitted
+
#![feature(staged_api)]
+//~^ ERROR module has missing stability attribute
-#[stable(feature = "x", since = "1")]
+#[stable(feature = "a", since = "1")]
struct StableType;
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "b", issue = "none")]
struct UnstableType;
-#[stable(feature = "x", since = "1")]
+#[stable(feature = "c", since = "1")]
trait StableTrait {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "d", issue = "none")]
trait UnstableTrait {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "e", issue = "none")]
impl UnstableTrait for UnstableType {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "f", issue = "none")]
impl StableTrait for UnstableType {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "g", issue = "none")]
impl UnstableTrait for StableType {}
-#[unstable(feature = "x", issue = "none")]
+#[unstable(feature = "h", issue = "none")]
//~^ ERROR an `#[unstable]` annotation here has no effect [ineffective_unstable_trait_impl]
impl StableTrait for StableType {}
error: an `#[unstable]` annotation here has no effect
- --> $DIR/stability-attribute-trait-impl.rs:24:1
+ --> $DIR/stability-attribute-trait-impl.rs:25:1
|
-LL | #[unstable(feature = "x", issue = "none")]
+LL | #[unstable(feature = "h", issue = "none")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[deny(ineffective_unstable_trait_impl)]` on by default
= note: see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
-error: aborting due to previous error
+error: module has missing stability attribute
+ --> $DIR/stability-attribute-trait-impl.rs:1:1
+ |
+LL | / #![feature(staged_api)]
+LL | |
+LL | |
+LL | | #[stable(feature = "a", since = "1")]
+... |
+LL | |
+LL | | fn main() {}
+ | |____________^
+
+error: aborting due to 2 previous errors
--- /dev/null
+// original problem
+pub fn foo<T>() -> isize {
+ {
+ static foo: isize = 2;
+ foo
+ }
+}
+
+// issue 8134
+struct Foo;
+impl Foo {
+ pub fn foo<T>(&self) {
+ static X: usize = 1;
+ }
+}
+
+// issue 8134
+pub struct Parser<T>(T);
+impl<T: std::iter::Iterator<Item=char>> Parser<T> {
+ fn in_doctype(&mut self) {
+ static DOCTYPEPattern: [char; 6] = ['O', 'C', 'T', 'Y', 'P', 'E'];
+ }
+}
+
+struct Bar;
+impl Foo {
+ pub fn bar<T>(&self) {
+ static X: usize = 1;
+ }
+}
--- /dev/null
+// run-pass
+// aux-build:nested_item.rs
+
+
+extern crate nested_item;
+
+pub fn main() {
+ assert_eq!(2, nested_item::foo::<()>());
+ assert_eq!(2, nested_item::foo::<isize>());
+}
--- /dev/null
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-14227.rs:7:21
+ |
+LL | static CRASH: u32 = symbol;
+ | ^^^^^^ use of extern static
+ |
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
--- /dev/null
+// revisions: mir thir
+// [thir]compile-flags: -Z thir-unsafeck
+
+extern "C" {
+ pub static symbol: u32;
+}
+static CRASH: u32 = symbol;
+//~^ ERROR use of extern static is unsafe and requires
+
+fn main() {}
--- /dev/null
+error[E0133]: use of extern static is unsafe and requires unsafe function or block
+ --> $DIR/issue-14227.rs:7:21
+ |
+LL | static CRASH: u32 = symbol;
+ | ^^^^^^ use of extern static
+ |
+ = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0133`.
static VOID2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
+//~| ERROR undefined behavior to use this value
+//~| WARN: type `Void` does not permit zero-initialization
static NEVER2: Void = unsafe { std::mem::transmute(()) }; //~ ERROR static of uninhabited type
//~| WARN: previously accepted
+//~| ERROR undefined behavior to use this value
+//~| WARN: type `Void` does not permit zero-initialization
fn main() {}
= note: uninhabited statics cannot be initialized, and any access would be an immediate error
error: static of uninhabited type
- --> $DIR/uninhabited-static.rs:14:1
+ --> $DIR/uninhabited-static.rs:16:1
|
LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: for more information, see issue #74840 <https://github.com/rust-lang/rust/issues/74840>
= note: uninhabited statics cannot be initialized, and any access would be an immediate error
-error: aborting due to 4 previous errors
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/uninhabited-static.rs:12:1
+ |
+LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 0, align: 1) {}
+
+error[E0080]: it is undefined behavior to use this value
+ --> $DIR/uninhabited-static.rs:16:1
+ |
+LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of uninhabited type Void
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+ = note: the raw bytes of the constant (size: 0, align: 1) {}
+
+warning: the type `Void` does not permit zero-initialization
+ --> $DIR/uninhabited-static.rs:12:31
+ |
+LL | static VOID2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | this code causes undefined behavior when executed
+ | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+ |
+ = note: `#[warn(invalid_value)]` on by default
+ = note: enums with no variants have no valid value
+
+warning: the type `Void` does not permit zero-initialization
+ --> $DIR/uninhabited-static.rs:16:32
+ |
+LL | static NEVER2: Void = unsafe { std::mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | this code causes undefined behavior when executed
+ | help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+ |
+ = note: enums with no variants have no valid value
+
+error: aborting due to 6 previous errors; 2 warnings emitted
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// run-pass
+enum Void {}
+fn foo(_: Result<(Void, u32), (Void, String)>) {}
+fn main() {
+ let _: fn(_) = foo;
+}
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "illumos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
+++ /dev/null
-// run-pass
-
-#![allow(non_camel_case_types)]
-
-
-#[derive(Copy, Clone, Debug)]
-enum foo { large, small, }
-
-impl PartialEq for foo {
- fn eq(&self, other: &foo) -> bool {
- ((*self) as usize) == ((*other) as usize)
- }
- fn ne(&self, other: &foo) -> bool { !(*self).eq(other) }
-}
-
-pub fn main() {
- let a = (1, 2, 3);
- let b = (1, 2, 3);
- assert_eq!(a, b);
- assert!((a != (1, 2, 4)));
- assert!((a < (1, 2, 4)));
- assert!((a <= (1, 2, 4)));
- assert!(((1, 2, 4) > a));
- assert!(((1, 2, 4) >= a));
- let x = foo::large;
- let y = foo::small;
- assert!((x != y));
- assert_eq!(x, foo::large);
- assert!((x != foo::small));
-}
--- /dev/null
+enum Ty {
+ Unit,
+ List(Box<Ty>),
+}
+
+fn foo(x: Ty) -> Ty {
+ match x {
+ Ty::Unit => Ty::Unit,
+ Ty::List(elem) => foo(elem),
+ //~^ ERROR mismatched types
+ //~| HELP try dereferencing the `Box`
+ //~| HELP try using a variant of the expected enum
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/boxed-variant-field.rs:9:31
+ |
+LL | Ty::List(elem) => foo(elem),
+ | ^^^^ expected enum `Ty`, found struct `Box`
+ |
+ = note: expected enum `Ty`
+ found struct `Box<Ty>`
+help: try dereferencing the `Box`
+ |
+LL | Ty::List(elem) => foo(*elem),
+ | +
+help: try using a variant of the expected enum
+ |
+LL | Ty::List(elem) => foo(Ty::List(elem)),
+ | ~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
error[E0277]: the trait bound `&str: From<String>` is not satisfied
- --> $DIR/into-str.rs:4:5
+ --> $DIR/into-str.rs:4:9
|
LL | foo(String::new());
- | ^^^ the trait `From<String>` is not implemented for `&str`
+ | --- ^^^^^^^^^^^^^ the trait `From<String>` is not implemented for `&str`
+ | |
+ | required by a bound introduced by this call
|
= note: to coerce a `String` into a `&str`, use `&*` as a prefix
= note: required because of the requirements on the impl of `Into<&str>` for `String`
--- /dev/null
+// Make sure that trying to access `TryInto`, `TryFrom`, `FromIterator` in pre-2021 mentions
+// Edition 2021 change
+// edition:2018
+
+fn test() {
+ let _i: i16 = 0_i32.try_into().unwrap();
+ //~^ ERROR no method named `try_into` found for type `i32` in the current scope
+ //~| NOTE method not found in `i32`
+ //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+
+ let _i: i16 = TryFrom::try_from(0_i32).unwrap();
+ //~^ ERROR failed to resolve: use of undeclared type
+ //~| NOTE not found in this scope
+ //~| NOTE 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
+ //~| NOTE 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
+
+ let _i: i16 = TryInto::try_into(0_i32).unwrap();
+ //~^ ERROR failed to resolve: use of undeclared type
+ //~| NOTE not found in this scope
+ //~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+ //~| NOTE 'core::convert::TryInto' is included in the prelude starting in Edition 2021
+
+ let _v: Vec<_> = FromIterator::from_iter(&[1]);
+ //~^ ERROR failed to resolve: use of undeclared type
+ //~| NOTE 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
+ //~| NOTE 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
+}
+
+fn main() {
+ test();
+}
--- /dev/null
+error[E0433]: failed to resolve: use of undeclared type `TryFrom`
+ --> $DIR/suggest-tryinto-edition-change.rs:11:19
+ |
+LL | let _i: i16 = TryFrom::try_from(0_i32).unwrap();
+ | ^^^^^^^ not found in this scope
+ |
+ = note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
+ = note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
+help: consider importing one of these items
+ |
+LL | use core::convert::TryFrom;
+ |
+LL | use std::convert::TryFrom;
+ |
+
+error[E0433]: failed to resolve: use of undeclared type `TryInto`
+ --> $DIR/suggest-tryinto-edition-change.rs:17:19
+ |
+LL | let _i: i16 = TryInto::try_into(0_i32).unwrap();
+ | ^^^^^^^ not found in this scope
+ |
+ = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+ = note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021
+help: consider importing one of these items
+ |
+LL | use core::convert::TryInto;
+ |
+LL | use std::convert::TryInto;
+ |
+
+error[E0433]: failed to resolve: use of undeclared type `FromIterator`
+ --> $DIR/suggest-tryinto-edition-change.rs:23:22
+ |
+LL | let _v: Vec<_> = FromIterator::from_iter(&[1]);
+ | ^^^^^^^^^^^^
+ |
+ ::: $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+ |
+LL | pub trait IntoIterator {
+ | ---------------------- similarly named trait `IntoIterator` defined here
+ |
+ = note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
+ = note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
+help: a trait with a similar name exists
+ |
+LL | let _v: Vec<_> = IntoIterator::from_iter(&[1]);
+ | ~~~~~~~~~~~~
+help: consider importing one of these items
+ |
+LL | use core::iter::FromIterator;
+ |
+LL | use std::iter::FromIterator;
+ |
+
+error[E0599]: no method named `try_into` found for type `i32` in the current scope
+ --> $DIR/suggest-tryinto-edition-change.rs:6:25
+ |
+LL | let _i: i16 = 0_i32.try_into().unwrap();
+ | ^^^^^^^^ method not found in `i32`
+ |
+ ::: $SRC_DIR/core/src/convert/mod.rs:LL:COL
+ |
+LL | fn try_into(self) -> Result<T, Self::Error>;
+ | -------- the method is available for `i32` here
+ |
+ = help: items from traits can only be used if the trait is in scope
+ = note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+ |
+LL | use std::convert::TryInto;
+ |
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0433, E0599.
+For more information about an error, try `rustc --explain E0433`.
--- /dev/null
+// edition:2018
+
+use alloc::rc::Rc; //~ ERROR failed to resolve: use of undeclared crate or module `alloc`
+
+fn main() {}
--- /dev/null
+error[E0433]: failed to resolve: use of undeclared crate or module `alloc`
+ --> $DIR/undeclared-module-alloc.rs:3:5
+ |
+LL | use alloc::rc::Rc;
+ | ^^^^^ use of undeclared crate or module `alloc`
+ |
+ = help: add `extern crate alloc` to use the `alloc` crate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0433`.
+++ /dev/null
-// run-pass
-
-pub fn main() {
- let f = 1_usize as *const String;
- println!("{:?}", f as isize);
- println!("{:?}", f as usize);
- println!("{:?}", f as i8);
- println!("{:?}", f as i16);
- println!("{:?}", f as i32);
- println!("{:?}", f as i64);
- println!("{:?}", f as u8);
- println!("{:?}", f as u16);
- println!("{:?}", f as u32);
- println!("{:?}", f as u64);
-
- println!("{:?}", 1 as isize);
- println!("{:?}", 1 as usize);
- println!("{:?}", 1 as *const String);
- println!("{:?}", 1 as i8);
- println!("{:?}", 1 as i16);
- println!("{:?}", 1 as i32);
- println!("{:?}", 1 as i64);
- println!("{:?}", 1 as u8);
- println!("{:?}", 1 as u16);
- println!("{:?}", 1 as u32);
- println!("{:?}", 1 as u64);
- println!("{:?}", 1 as f32);
- println!("{:?}", 1 as f64);
-
- println!("{:?}", 1_usize as isize);
- println!("{:?}", 1_usize as usize);
- println!("{:?}", 1_usize as *const String);
- println!("{:?}", 1_usize as i8);
- println!("{:?}", 1_usize as i16);
- println!("{:?}", 1_usize as i32);
- println!("{:?}", 1_usize as i64);
- println!("{:?}", 1_usize as u8);
- println!("{:?}", 1_usize as u16);
- println!("{:?}", 1_usize as u32);
- println!("{:?}", 1_usize as u64);
- println!("{:?}", 1_usize as f32);
- println!("{:?}", 1_usize as f64);
-
- println!("{:?}", 1i8 as isize);
- println!("{:?}", 1i8 as usize);
- println!("{:?}", 1i8 as *const String);
- println!("{:?}", 1i8 as i8);
- println!("{:?}", 1i8 as i16);
- println!("{:?}", 1i8 as i32);
- println!("{:?}", 1i8 as i64);
- println!("{:?}", 1i8 as u8);
- println!("{:?}", 1i8 as u16);
- println!("{:?}", 1i8 as u32);
- println!("{:?}", 1i8 as u64);
- println!("{:?}", 1i8 as f32);
- println!("{:?}", 1i8 as f64);
-
- println!("{:?}", 1u8 as isize);
- println!("{:?}", 1u8 as usize);
- println!("{:?}", 1u8 as *const String);
- println!("{:?}", 1u8 as i8);
- println!("{:?}", 1u8 as i16);
- println!("{:?}", 1u8 as i32);
- println!("{:?}", 1u8 as i64);
- println!("{:?}", 1u8 as u8);
- println!("{:?}", 1u8 as u16);
- println!("{:?}", 1u8 as u32);
- println!("{:?}", 1u8 as u64);
- println!("{:?}", 1u8 as f32);
- println!("{:?}", 1u8 as f64);
-
- println!("{:?}", 1i16 as isize);
- println!("{:?}", 1i16 as usize);
- println!("{:?}", 1i16 as *const String);
- println!("{:?}", 1i16 as i8);
- println!("{:?}", 1i16 as i16);
- println!("{:?}", 1i16 as i32);
- println!("{:?}", 1i16 as i64);
- println!("{:?}", 1i16 as u8);
- println!("{:?}", 1i16 as u16);
- println!("{:?}", 1i16 as u32);
- println!("{:?}", 1i16 as u64);
- println!("{:?}", 1i16 as f32);
- println!("{:?}", 1i16 as f64);
-
- println!("{:?}", 1u16 as isize);
- println!("{:?}", 1u16 as usize);
- println!("{:?}", 1u16 as *const String);
- println!("{:?}", 1u16 as i8);
- println!("{:?}", 1u16 as i16);
- println!("{:?}", 1u16 as i32);
- println!("{:?}", 1u16 as i64);
- println!("{:?}", 1u16 as u8);
- println!("{:?}", 1u16 as u16);
- println!("{:?}", 1u16 as u32);
- println!("{:?}", 1u16 as u64);
- println!("{:?}", 1u16 as f32);
- println!("{:?}", 1u16 as f64);
-
- println!("{:?}", 1i32 as isize);
- println!("{:?}", 1i32 as usize);
- println!("{:?}", 1i32 as *const String);
- println!("{:?}", 1i32 as i8);
- println!("{:?}", 1i32 as i16);
- println!("{:?}", 1i32 as i32);
- println!("{:?}", 1i32 as i64);
- println!("{:?}", 1i32 as u8);
- println!("{:?}", 1i32 as u16);
- println!("{:?}", 1i32 as u32);
- println!("{:?}", 1i32 as u64);
- println!("{:?}", 1i32 as f32);
- println!("{:?}", 1i32 as f64);
-
- println!("{:?}", 1u32 as isize);
- println!("{:?}", 1u32 as usize);
- println!("{:?}", 1u32 as *const String);
- println!("{:?}", 1u32 as i8);
- println!("{:?}", 1u32 as i16);
- println!("{:?}", 1u32 as i32);
- println!("{:?}", 1u32 as i64);
- println!("{:?}", 1u32 as u8);
- println!("{:?}", 1u32 as u16);
- println!("{:?}", 1u32 as u32);
- println!("{:?}", 1u32 as u64);
- println!("{:?}", 1u32 as f32);
- println!("{:?}", 1u32 as f64);
-
- println!("{:?}", 1i64 as isize);
- println!("{:?}", 1i64 as usize);
- println!("{:?}", 1i64 as *const String);
- println!("{:?}", 1i64 as i8);
- println!("{:?}", 1i64 as i16);
- println!("{:?}", 1i64 as i32);
- println!("{:?}", 1i64 as i64);
- println!("{:?}", 1i64 as u8);
- println!("{:?}", 1i64 as u16);
- println!("{:?}", 1i64 as u32);
- println!("{:?}", 1i64 as u64);
- println!("{:?}", 1i64 as f32);
- println!("{:?}", 1i64 as f64);
-
- println!("{:?}", 1u64 as isize);
- println!("{:?}", 1u64 as usize);
- println!("{:?}", 1u64 as *const String);
- println!("{:?}", 1u64 as i8);
- println!("{:?}", 1u64 as i16);
- println!("{:?}", 1u64 as i32);
- println!("{:?}", 1u64 as i64);
- println!("{:?}", 1u64 as u8);
- println!("{:?}", 1u64 as u16);
- println!("{:?}", 1u64 as u32);
- println!("{:?}", 1u64 as u64);
- println!("{:?}", 1u64 as f32);
- println!("{:?}", 1u64 as f64);
-
- println!("{:?}", 1u64 as isize);
- println!("{:?}", 1u64 as usize);
- println!("{:?}", 1u64 as *const String);
- println!("{:?}", 1u64 as i8);
- println!("{:?}", 1u64 as i16);
- println!("{:?}", 1u64 as i32);
- println!("{:?}", 1u64 as i64);
- println!("{:?}", 1u64 as u8);
- println!("{:?}", 1u64 as u16);
- println!("{:?}", 1u64 as u32);
- println!("{:?}", 1u64 as u64);
- println!("{:?}", 1u64 as f32);
- println!("{:?}", 1u64 as f64);
-
- println!("{:?}", true as isize);
- println!("{:?}", true as usize);
- println!("{:?}", true as i8);
- println!("{:?}", true as i16);
- println!("{:?}", true as i32);
- println!("{:?}", true as i64);
- println!("{:?}", true as u8);
- println!("{:?}", true as u16);
- println!("{:?}", true as u32);
- println!("{:?}", true as u64);
-
- println!("{:?}", 1f32 as isize);
- println!("{:?}", 1f32 as usize);
- println!("{:?}", 1f32 as i8);
- println!("{:?}", 1f32 as i16);
- println!("{:?}", 1f32 as i32);
- println!("{:?}", 1f32 as i64);
- println!("{:?}", 1f32 as u8);
- println!("{:?}", 1f32 as u16);
- println!("{:?}", 1f32 as u32);
- println!("{:?}", 1f32 as u64);
- println!("{:?}", 1f32 as f32);
- println!("{:?}", 1f32 as f64);
-
- println!("{:?}", 1f64 as isize);
- println!("{:?}", 1f64 as usize);
- println!("{:?}", 1f64 as i8);
- println!("{:?}", 1f64 as i16);
- println!("{:?}", 1f64 as i32);
- println!("{:?}", 1f64 as i64);
- println!("{:?}", 1f64 as u8);
- println!("{:?}", 1f64 as u16);
- println!("{:?}", 1f64 as u32);
- println!("{:?}", 1f64 as u64);
- println!("{:?}", 1f64 as f32);
- println!("{:?}", 1f64 as f64);
-}
--- /dev/null
+#![crate_name = "a"]
+
+pub fn foo<T>() {}
--- /dev/null
+#![crate_name = "a"]
+
+pub fn foo<T>() { println!("hello!"); }
--- /dev/null
+#![crate_name = "b"]
+
+extern crate a;
+
+pub fn foo() { a::foo::<isize>(); }
--- /dev/null
+// ignore-msvc FIXME #31306
+
+// note that these aux-build directives must be in this order
+// aux-build:changing-crates-a1.rs
+// aux-build:changing-crates-b.rs
+// aux-build:changing-crates-a2.rs
+// normalize-stderr-test: "(crate `(\w+)`:) .*" -> "$1 $$PATH_$2"
+
+extern crate a;
+extern crate b; //~ ERROR: found possibly newer version of crate `a` which `b` depends on
+
+fn main() {}
--- /dev/null
+error[E0460]: found possibly newer version of crate `a` which `b` depends on
+ --> $DIR/changing-crates.rs:10:1
+ |
+LL | extern crate b;
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: perhaps that crate needs to be recompiled?
+ = note: the following crate versions were found:
+ crate `a`: $PATH_a
+ crate `b`: $PATH_b
+
+error: aborting due to previous error
+
+++ /dev/null
-#![feature(negative_impls)]
-
-use std::marker::Send;
-
-struct TestType;
-
-impl !TestType {}
-//~^ ERROR inherent impls cannot be negative
-
-trait TestTrait {}
-
-unsafe impl !Send for TestType {}
-//~^ ERROR negative impls cannot be unsafe
-impl !TestTrait for TestType {}
-
-struct TestType2<T>(T);
-
-impl<T> !TestType2<T> {}
-//~^ ERROR inherent impls cannot be negative
-
-unsafe impl<T> !Send for TestType2<T> {}
-//~^ ERROR negative impls cannot be unsafe
-impl<T> !TestTrait for TestType2<T> {}
-
-fn main() {}
+++ /dev/null
-error: inherent impls cannot be negative
- --> $DIR/syntax-trait-polarity.rs:7:7
- |
-LL | impl !TestType {}
- | -^^^^^^^^ inherent impl for this type
- | |
- | negative because of this
-
-error[E0198]: negative impls cannot be unsafe
- --> $DIR/syntax-trait-polarity.rs:12:13
- |
-LL | unsafe impl !Send for TestType {}
- | ------ -^^^^
- | | |
- | | negative because of this
- | unsafe because of this
-
-error: inherent impls cannot be negative
- --> $DIR/syntax-trait-polarity.rs:18:10
- |
-LL | impl<T> !TestType2<T> {}
- | -^^^^^^^^^^^^ inherent impl for this type
- | |
- | negative because of this
-
-error[E0198]: negative impls cannot be unsafe
- --> $DIR/syntax-trait-polarity.rs:21:16
- |
-LL | unsafe impl<T> !Send for TestType2<T> {}
- | ------ -^^^^
- | | |
- | | negative because of this
- | unsafe because of this
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0198`.
|
LL | func::<u8>(42);
| ^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
--> $DIR/synthetic-param.rs:23:17
|
LL | Foo::func::<u8>(42);
| ^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error[E0632]: cannot provide explicit generic arguments when `impl Trait` is used in argument position
--> $DIR/synthetic-param.rs:26:23
|
LL | Bar::<i8>::func::<u8>(42);
| ^^ explicit generic argument not allowed
+ |
+ = note: see issue #83701 <https://github.com/rust-lang/rust/issues/83701> for more information
+ = help: add `#![feature(explicit_generic_args_with_impl_trait)]` to the crate attributes to enable
error: aborting due to 3 previous errors
+++ /dev/null
-// run-pass
-// ignore-emscripten no threads support
-
-// Issue #787
-// Don't try to clean up uninitialized locals
-
-
-use std::thread;
-
-fn test_break() { loop { let _x: Box<isize> = break; } }
-
-fn test_cont() { let mut i = 0; while i < 1 { i += 1; let _x: Box<isize> = continue; } }
-
-fn test_ret() { let _x: Box<isize> = return; }
-
-fn test_panic() {
- fn f() { let _x: Box<isize> = panic!(); }
- thread::spawn(move|| f() ).join().unwrap_err();
-}
-
-fn test_panic_indirect() {
- fn f() -> ! { panic!(); }
- fn g() { let _x: Box<isize> = f(); }
- thread::spawn(move|| g() ).join().unwrap_err();
-}
-
-pub fn main() {
- test_break();
- test_cont();
- test_ret();
- test_panic();
- test_panic_indirect();
-}
|
= note: expected struct `Foo`
found struct `Box<Foo>`
+help: try dereferencing the `Box`
+ |
+LL | want_foo(*b);
+ | +
error: aborting due to previous error
--- /dev/null
+// run-pass
+// compile-flags: --test
+
+#[test]
+pub fn foo() {}
+++ /dev/null
-// run-pass
-// compile-flags: -Z thinlto -C codegen-units=2
-
-#[global_allocator]
-static A: std::alloc::System = std::alloc::System;
-
-fn main() {}
+++ /dev/null
-// run-pass
-
-// compile-flags: -Clto=thin
-// no-prefer-dynamic
-
-fn main() {
- println!("hello!");
-}
+++ /dev/null
-// compile-flags: -Z thinlto -C codegen-units=8
-
-#[inline]
-pub fn foo(b: u8) {
- b.to_string();
-}
+++ /dev/null
-// no-prefer-dynamic
-// compile-flags: -Z thinlto -C codegen-units=8 -C prefer-dynamic
-
-#![crate_type = "rlib"]
-#![crate_type = "dylib"]
-
-pub static A: u32 = 43;
-
-pub mod a {
- pub static A: u32 = 43;
-}
+++ /dev/null
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-pub fn bar() -> u32 {
- 3
-}
+++ /dev/null
-// run-pass
-
-// aux-build:dylib.rs
-
-extern crate dylib;
-
-fn main() {
- dylib::foo(1);
-}
+++ /dev/null
-// run-pass
-
-// aux-build:msvc-imp-present.rs
-// compile-flags: -Z thinlto -C codegen-units=8
-// no-prefer-dynamic
-
-// On MSVC we have a "hack" where we emit symbols that look like `_imp_$name`
-// for all exported statics. This is done because we apply `dllimport` to all
-// imported constants and this allows everything to actually link correctly.
-//
-// The ThinLTO passes aggressively remove symbols if they can, and this test
-// asserts that the ThinLTO passes don't remove these compiler-generated
-// `_imp_*` symbols. The external library that we link in here is compiled with
-// ThinLTO and multiple codegen units and has a few exported constants. Note
-// that we also namely compile the library as both a dylib and an rlib, but we
-// link the rlib to ensure that we assert those generated symbols exist.
-
-extern crate msvc_imp_present as bar;
-
-fn main() {
- println!("{}", bar::A);
-}
+++ /dev/null
-// run-pass
-
-// compile-flags: -Z thinlto -C codegen-units=8 -O
-// ignore-emscripten can't inspect instructions on emscripten
-
-// We want to assert here that ThinLTO will inline across codegen units. There's
-// not really a great way to do that in general so we sort of hack around it by
-// praying two functions go into separate codegen units and then assuming that
-// if inlining *doesn't* happen the first byte of the functions will differ.
-
-pub fn foo() -> u32 {
- bar::bar()
-}
-
-mod bar {
- pub fn bar() -> u32 {
- 3
- }
-}
-
-fn main() {
- println!("{} {}", foo(), bar::bar());
-
- unsafe {
- let foo = foo as usize as *const u8;
- let bar = bar::bar as usize as *const u8;
-
- assert_eq!(*foo, *bar);
- }
-}
+++ /dev/null
-// run-pass
-
-// compile-flags: -C codegen-units=8 -O -C lto=thin
-// aux-build:thin-lto-inlines-aux.rs
-// no-prefer-dynamic
-// ignore-emscripten can't inspect instructions on emscripten
-
-// We want to assert here that ThinLTO will inline across codegen units. There's
-// not really a great way to do that in general so we sort of hack around it by
-// praying two functions go into separate codegen units and then assuming that
-// if inlining *doesn't* happen the first byte of the functions will differ.
-
-extern crate thin_lto_inlines_aux as bar;
-
-pub fn foo() -> u32 {
- bar::bar()
-}
-
-fn main() {
- println!("{} {}", foo(), bar::bar());
-
- unsafe {
- let foo = foo as usize as *const u8;
- let bar = bar::bar as usize as *const u8;
-
- assert_eq!(*foo, *bar);
- }
-}
+++ /dev/null
-// run-pass
-
-// compile-flags: -C codegen-units=8 -Z thinlto
-// ignore-windows
-
-#![feature(linkage)]
-
-pub mod foo {
- #[linkage = "weak"]
- #[no_mangle]
- pub extern "C" fn FOO() -> i32 {
- 0
- }
-}
-
-mod bar {
- extern "C" {
- fn FOO() -> i32;
- }
-
- pub fn bar() -> i32 {
- unsafe { FOO() }
- }
-}
-
-fn main() {
- bar::bar();
-}
--- /dev/null
+// run-pass
+// ignore-emscripten no threads
+// ignore-sgx no processes
+
+use std::thread;
+use std::env;
+use std::process::Command;
+
+struct Handle(i32);
+
+impl Drop for Handle {
+ fn drop(&mut self) { panic!(); }
+}
+
+thread_local!(static HANDLE: Handle = Handle(0));
+
+fn main() {
+ let args = env::args().collect::<Vec<_>>();
+ if args.len() == 1 {
+ let out = Command::new(&args[0]).arg("test").output().unwrap();
+ let stderr = std::str::from_utf8(&out.stderr).unwrap();
+ assert!(stderr.contains("panicked at 'explicit panic'"),
+ "bad failure message:\n{}\n", stderr);
+ } else {
+ // TLS dtors are not always run on process exit
+ thread::spawn(|| {
+ HANDLE.with(|h| {
+ println!("{}", h.0);
+ });
+ }).join().unwrap();
+ }
+}
--- /dev/null
+// run-pass
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::channel;
+use std::thread;
+
+pub fn main() {
+ let (tx, rx) = channel::<&'static str>();
+
+ let t = thread::spawn(move|| {
+ assert_eq!(rx.recv().unwrap(), "hello, world");
+ });
+
+ tx.send("hello, world").unwrap();
+ t.join().ok().unwrap();
+}
--- /dev/null
+// run-pass
+// ignore-emscripten no threads support
+
+use std::thread;
+use std::sync::mpsc::{channel, Receiver};
+
+fn periodical(n: isize) -> Receiver<bool> {
+ let (chan, port) = channel();
+ thread::spawn(move|| {
+ loop {
+ for _ in 1..n {
+ match chan.send(false) {
+ Ok(()) => {}
+ Err(..) => break,
+ }
+ }
+ match chan.send(true) {
+ Ok(()) => {}
+ Err(..) => break
+ }
+ }
+ });
+ return port;
+}
+
+fn integers() -> Receiver<isize> {
+ let (chan, port) = channel();
+ thread::spawn(move|| {
+ let mut i = 1;
+ loop {
+ match chan.send(i) {
+ Ok(()) => {}
+ Err(..) => break,
+ }
+ i = i + 1;
+ }
+ });
+ return port;
+}
+
+fn main() {
+ let ints = integers();
+ let threes = periodical(3);
+ let fives = periodical(5);
+ for _ in 1..100 {
+ match (ints.recv().unwrap(), threes.recv().unwrap(), fives.recv().unwrap()) {
+ (_, true, true) => println!("FizzBuzz"),
+ (_, true, false) => println!("Fizz"),
+ (_, false, true) => println!("Buzz"),
+ (i, false, false) => println!("{}", i)
+ }
+ }
+}
--- /dev/null
+// run-pass
+#![allow(unused_must_use)]
+#![allow(deprecated)]
+// ignore-emscripten no threads support
+
+use std::sync::mpsc::{TryRecvError, channel};
+use std::thread;
+
+pub fn main() {
+ let (tx, rx) = channel();
+ let t = thread::spawn(move||{
+ thread::sleep_ms(10);
+ tx.send(()).unwrap();
+ });
+ loop {
+ match rx.try_recv() {
+ Ok(()) => break,
+ Err(TryRecvError::Empty) => {}
+ Err(TryRecvError::Disconnected) => unreachable!()
+ }
+ }
+ t.join();
+}
--- /dev/null
+// run-pass
+
+#![allow(unused_must_use)]
+/*
+ This is about the simplest program that can successfully send a
+ message.
+ */
+
+use std::sync::mpsc::channel;
+
+pub fn main() {
+ let (tx, rx) = channel();
+ tx.send(42);
+ let r = rx.recv();
+ println!("{:?}", r);
+}
--- /dev/null
+// run-pass
+
+use std::thread;
+
+pub fn main() {
+ let mut i: isize = 0;
+ while i < 100 { i = i + 1; println!("{}", i); thread::yield_now(); }
+}
+++ /dev/null
-#![feature(trace_macros)]
-
-fn main() {
- trace_macros!(); //~ ERROR trace_macros! accepts only `true` or `false`
- trace_macros!(1); //~ ERROR trace_macros! accepts only `true` or `false`
- trace_macros!(ident); //~ ERROR trace_macros! accepts only `true` or `false`
- trace_macros!(for); //~ ERROR trace_macros! accepts only `true` or `false`
- trace_macros!(true,); //~ ERROR trace_macros! accepts only `true` or `false`
- trace_macros!(false 1); //~ ERROR trace_macros! accepts only `true` or `false`
-
-
- // should be fine:
- macro_rules! expando {
- ($x: ident) => { trace_macros!($x) }
- }
-
- expando!(true);
-}
+++ /dev/null
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:4:5
- |
-LL | trace_macros!();
- | ^^^^^^^^^^^^^^^
-
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:5:5
- |
-LL | trace_macros!(1);
- | ^^^^^^^^^^^^^^^^
-
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:6:5
- |
-LL | trace_macros!(ident);
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:7:5
- |
-LL | trace_macros!(for);
- | ^^^^^^^^^^^^^^^^^^
-
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:8:5
- |
-LL | trace_macros!(true,);
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: trace_macros! accepts only `true` or `false`
- --> $DIR/trace_macros-format.rs:9:5
- |
-LL | trace_macros!(false 1);
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 6 previous errors
-
--- /dev/null
+// check-pass
+
+pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
+ <&mut () as Clone>::clone(&s);
+}
+
+fn main() {}
--- /dev/null
+// run-pass
+
+trait Foo: Fn(i32) -> i32 + Send {}
+
+impl<T: ?Sized + Fn(i32) -> i32 + Send> Foo for T {}
+
+fn wants_foo(f: Box<dyn Foo>) -> i32 {
+ f(42)
+}
+
+fn main() {
+ let f = Box::new(|x| x);
+ assert_eq!(wants_foo(f), 42);
+}
--- /dev/null
+trait Q<T:?Sized> {}
+trait Foo where u32: Q<Self> {
+ fn foo(&self);
+}
+
+impl Q<()> for u32 {}
+impl Foo for () {
+ fn foo(&self) {
+ println!("foo!");
+ }
+}
+
+fn main() {
+ let _f: Box<dyn Foo> = //~ ERROR `Foo` cannot be made into an object
+ Box::new(()); //~ ERROR `Foo` cannot be made into an object
+}
--- /dev/null
+error[E0038]: the trait `Foo` cannot be made into an object
+ --> $DIR/issue-38604.rs:14:13
+ |
+LL | let _f: Box<dyn Foo> =
+ | ^^^^^^^^^^^^ `Foo` cannot be made into an object
+ |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+ --> $DIR/issue-38604.rs:2:22
+ |
+LL | trait Foo where u32: Q<Self> {
+ | --- ^^^^^^^ ...because it uses `Self` as a type parameter
+ | |
+ | this trait cannot be made into an object...
+
+error[E0038]: the trait `Foo` cannot be made into an object
+ --> $DIR/issue-38604.rs:15:9
+ |
+LL | Box::new(());
+ | ^^^^^^^^^^^^ `Foo` cannot be made into an object
+ |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+ --> $DIR/issue-38604.rs:2:22
+ |
+LL | trait Foo where u32: Q<Self> {
+ | --- ^^^^^^^ ...because it uses `Self` as a type parameter
+ | |
+ | this trait cannot be made into an object...
+ = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn Foo>>` for `Box<()>`
+ = note: required by cast to type `Box<dyn Foo>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
--- /dev/null
+struct Point {
+ x: f64,
+ y: f64,
+}
+
+trait ToString_ {
+ fn to_string(&self) -> String;
+}
+
+impl ToString_ for Point {
+ fn new(x: f64, y: f64) -> Point {
+ //~^ ERROR method `new` is not a member of trait `ToString_`
+ Point { x: x, y: y }
+ }
+
+ fn to_string(&self) -> String {
+ format!("({}, {})", self.x, self.y)
+ }
+}
+
+fn main() {
+ let p = Point::new(0.0, 0.0);
+ //~^ ERROR no function or associated item named `new` found for struct `Point`
+ println!("{}", p.to_string());
+}
--- /dev/null
+error[E0407]: method `new` is not a member of trait `ToString_`
+ --> $DIR/issue-3973.rs:11:5
+ |
+LL | / fn new(x: f64, y: f64) -> Point {
+LL | |
+LL | | Point { x: x, y: y }
+LL | | }
+ | |_____^ not a member of trait `ToString_`
+
+error[E0599]: no function or associated item named `new` found for struct `Point` in the current scope
+ --> $DIR/issue-3973.rs:22:20
+ |
+LL | struct Point {
+ | ------------ function or associated item `new` not found for this
+...
+LL | let p = Point::new(0.0, 0.0);
+ | ^^^ function or associated item not found in `Point`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0407, E0599.
+For more information about an error, try `rustc --explain E0407`.
--- /dev/null
+#![feature(trait_alias)]
+
+trait Svc<Req> { type Res; }
+
+trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
+//~^ ERROR associated type `Res` not found for `Self`
+//~| ERROR associated type `Res` not found for `Self`
+
+fn main() {}
--- /dev/null
+error[E0220]: associated type `Res` not found for `Self`
+ --> $DIR/issue-59029-1.rs:5:52
+ |
+LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
+ | ^^^ associated type `Res` not found
+
+error[E0220]: associated type `Res` not found for `Self`
+ --> $DIR/issue-59029-1.rs:5:52
+ |
+LL | trait MkSvc<Target, Req> = Svc<Target> where Self::Res: Svc<Req>;
+ | ^^^ associated type `Res` not found
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0220`.
| ----- in this derive macro expansion
LL | struct FooHolster {
LL | the_foos: Vec<Foo>,
- | ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
+ | ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `Foo`
|
= note: required because of the requirements on the impl of `Clone` for `Vec<Foo>`
note: required by `clone`
--- /dev/null
+// check-pass
+
+pub trait ResultExt {
+ type Ok;
+ fn err_eprint_and_ignore(self) -> Option<Self::Ok>;
+}
+
+impl<O, E> ResultExt for std::result::Result<O, E>
+where
+ E: std::error::Error,
+{
+ type Ok = O;
+ fn err_eprint_and_ignore(self) -> Option<O>
+ where
+ Self: ,
+ {
+ match self {
+ Err(e) => {
+ eprintln!("{}", e);
+ None
+ }
+ Ok(o) => Some(o),
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+pub trait Archive {
+ type Archived;
+}
+
+impl<T> Archive for Option<T> {
+ type Archived = ();
+}
+pub type Archived<T> = <T as Archive>::Archived;
+
+pub trait Deserialize<D> {}
+
+const ARRAY_SIZE: usize = 32;
+impl<__D> Deserialize<__D> for ()
+where
+ Option<[u8; ARRAY_SIZE]>: Archive,
+ Archived<Option<[u8; ARRAY_SIZE]>>: Deserialize<__D>,
+{
+}
+fn main() {}
--- /dev/null
+// check-pass
+pub trait Archive {
+ type Archived;
+}
+
+impl<T> Archive for Option<T> {
+ type Archived = ();
+}
+pub type Archived<T> = <T as Archive>::Archived;
+
+pub trait Deserialize<D> {}
+
+const ARRAY_SIZE: usize = 32;
+impl<__D> Deserialize<__D> for ()
+where
+ Option<[u8; ARRAY_SIZE]>: Archive,
+ Option<[u8; ARRAY_SIZE]>: Archive,
+ Archived<Option<[u8; ARRAY_SIZE]>>: Deserialize<__D>,
+{
+}
+fn main() {}
| |
| required by a bound introduced by this call
|
- = help: the trait `Send` is not implemented for `dummy1c::TestType`
+ = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType`
= note: required because it appears within the type `({integer}, dummy1c::TestType)`
note: required by a bound in `is_send`
--> $DIR/negated-auto-traits-error.rs:16:15
| |
| required by a bound introduced by this call
|
- = help: the trait `Send` is not implemented for `dummy3::TestType`
+ = help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType`
note: required because it appears within the type `Outer2<dummy3::TestType>`
--> $DIR/negated-auto-traits-error.rs:12:8
|
--- /dev/null
+// Test that an object type `Box<Foo>` is not considered to implement the
+// trait `Foo`. Issue #5087.
+
+trait Foo {}
+fn take_foo<F:Foo>(f: F) {}
+fn take_object(f: Box<dyn Foo>) { take_foo(f); }
+//~^ ERROR `Box<dyn Foo>: Foo` is not satisfied
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `Box<dyn Foo>: Foo` is not satisfied
+ --> $DIR/object-does-not-impl-trait.rs:6:44
+ |
+LL | fn take_object(f: Box<dyn Foo>) { take_foo(f); }
+ | -------- ^ the trait `Foo` is not implemented for `Box<dyn Foo>`
+ | |
+ | required by a bound introduced by this call
+ |
+note: required by a bound in `take_foo`
+ --> $DIR/object-does-not-impl-trait.rs:5:15
+ |
+LL | fn take_foo<F:Foo>(f: F) {}
+ | ^^^ required by this bound in `take_foo`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(negative_impls)]
+
+use std::marker::Send;
+
+struct TestType;
+
+impl !TestType {}
+//~^ ERROR inherent impls cannot be negative
+
+trait TestTrait {}
+
+unsafe impl !Send for TestType {}
+//~^ ERROR negative impls cannot be unsafe
+impl !TestTrait for TestType {}
+
+struct TestType2<T>(T);
+
+impl<T> !TestType2<T> {}
+//~^ ERROR inherent impls cannot be negative
+
+unsafe impl<T> !Send for TestType2<T> {}
+//~^ ERROR negative impls cannot be unsafe
+impl<T> !TestTrait for TestType2<T> {}
+
+fn main() {}
--- /dev/null
+error: inherent impls cannot be negative
+ --> $DIR/syntax-trait-polarity.rs:7:7
+ |
+LL | impl !TestType {}
+ | -^^^^^^^^ inherent impl for this type
+ | |
+ | negative because of this
+
+error[E0198]: negative impls cannot be unsafe
+ --> $DIR/syntax-trait-polarity.rs:12:13
+ |
+LL | unsafe impl !Send for TestType {}
+ | ------ -^^^^
+ | | |
+ | | negative because of this
+ | unsafe because of this
+
+error: inherent impls cannot be negative
+ --> $DIR/syntax-trait-polarity.rs:18:10
+ |
+LL | impl<T> !TestType2<T> {}
+ | -^^^^^^^^^^^^ inherent impl for this type
+ | |
+ | negative because of this
+
+error[E0198]: negative impls cannot be unsafe
+ --> $DIR/syntax-trait-polarity.rs:21:16
+ |
+LL | unsafe impl<T> !Send for TestType2<T> {}
+ | ------ -^^^^
+ | | |
+ | | negative because of this
+ | unsafe because of this
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0198`.
+++ /dev/null
-// run-pass
-
-#![feature(specialization)] //~ WARN the feature `specialization` is incomplete
-
-trait Specializable { type Output; }
-
-impl<T> Specializable for T {
- default type Output = u16;
-}
-
-fn main() {
- unsafe {
- std::mem::transmute::<u16, <() as Specializable>::Output>(0);
- }
-}
+++ /dev/null
-warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/transmute-specialization.rs:3:12
- |
-LL | #![feature(specialization)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
- = help: consider using `min_specialization` instead, which is more stable and complete
-
-warning: 1 warning emitted
-
+++ /dev/null
-// run-pass
-
-#![allow(unused_must_use)]
-/*
- This is about the simplest program that can successfully send a
- message.
- */
-
-use std::sync::mpsc::channel;
-
-pub fn main() {
- let (tx, rx) = channel();
- tx.send(42);
- let r = rx.recv();
- println!("{:?}", r);
-}
--- /dev/null
+// run-pass
+#![allow(unreachable_code)]
+// compile-flags: --edition 2018
+
+#![feature(try_blocks)]
+
+fn main() {
+ let mut a = 0;
+ let () = {
+ let _: Result<(), ()> = try {
+ let _ = Err(())?;
+ return
+ };
+ a += 1;
+ };
+ a += 2;
+ assert_eq!(a, 3);
+}
+++ /dev/null
-// compile-flags: --edition 2018
-fn foo() -> Result<(), ()> {
- Ok(try!()); //~ ERROR use of deprecated `try` macro
- Ok(try!(Ok(()))) //~ ERROR use of deprecated `try` macro
-}
-
-fn main() {
- let _ = foo();
-}
+++ /dev/null
-error: use of deprecated `try` macro
- --> $DIR/try-macro-suggestion.rs:3:8
- |
-LL | Ok(try!());
- | ^^^^^^
- |
- = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated
-help: you can still access the deprecated `try!()` macro using the "raw identifier" syntax
- |
-LL | Ok(r#try!());
- | ++
-
-error: use of deprecated `try` macro
- --> $DIR/try-macro-suggestion.rs:4:8
- |
-LL | Ok(try!(Ok(())))
- | ^^^^^^^^^^^^
- |
- = note: in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated
-help: you can use the `?` operator instead
- |
-LL - Ok(try!(Ok(())))
-LL + Ok(Ok(())?)
- |
-help: alternatively, you can still access the deprecated `try!()` macro using the "raw identifier" syntax
- |
-LL | Ok(r#try!(Ok(())))
- | ++
-
-error: aborting due to 2 previous errors
-
type V = u8;
fn f() -> Self::V { 0 }
//~^ ERROR ambiguous associated item
+ //~| ERROR ambiguous associated item
//~| WARN this was previously accepted
+ //~| WARN this was previously accepted
+ //~| HELP use fully-qualified syntax
//~| HELP use fully-qualified syntax
}
LL | type V;
| ^^^^^^^
-error: aborting due to previous error
+error: ambiguous associated item
+ --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:32:15
+ |
+LL | fn f() -> Self::V { 0 }
+ | ^^^^^^^ help: use fully-qualified syntax: `<E as Tr>::V`
+ |
+ = 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 #57644 <https://github.com/rust-lang/rust/issues/57644>
+note: `V` could refer to the variant defined here
+ --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:22:5
+ |
+LL | V
+ | ^
+note: `V` could also refer to the associated type defined here
+ --> $DIR/enum-variant-priority-lint-ambiguous_associated_items.rs:26:5
+ |
+LL | type V;
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
error[E0277]: `Rc<u32>` cannot be sent between threads safely
- --> $DIR/auto-trait-leakage2.rs:17:5
+ --> $DIR/auto-trait-leakage2.rs:17:13
|
LL | type Foo = impl std::fmt::Debug;
| -------------------- within this `impl Debug`
...
LL | is_send(m::foo());
- | ^^^^^^^ `Rc<u32>` cannot be sent between threads safely
+ | ------- ^^^^^^^^ `Rc<u32>` cannot be sent between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `impl Debug`, the trait `Send` is not implemented for `Rc<u32>`
= note: required because it appears within the type `impl Debug`
--- /dev/null
+// check-pass
+// compile-flags: -Z unpretty=hir
+
+#![feature(type_alias_impl_trait)]
+
+trait Animal {}
+
+fn main() {
+ pub type ServeFut = impl Animal;
+}
--- /dev/null
+// check-pass
+// compile-flags: -Z unpretty=hir
+
+#![feature(type_alias_impl_trait)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+trait Animal { }
+
+fn main() {
+ pub type ServeFut = /*impl Trait*/;
+ }
--- /dev/null
+// Regression test for #30225, which was an ICE that would trigger as
+// a result of a poor interaction between trait result caching and
+// type inference. Specifically, at that time, unification could cause
+// unrelated type variables to become instantiated, if subtyping
+// relationships existed. These relationships are now propagated
+// through obligations and hence everything works out fine.
+
+trait Foo<U,V> : Sized {
+ fn foo(self, u: Option<U>, v: Option<V>) {}
+}
+
+struct A;
+struct B;
+
+impl Foo<A, B> for () {} // impl A
+impl Foo<u32, u32> for u32 {} // impl B, creating ambiguity
+
+fn toxic() {
+ // cache the resolution <() as Foo<$0,$1>> = impl A
+ let u = None;
+ let v = None;
+ Foo::foo((), u, v);
+}
+
+fn bomb() {
+ let mut u = None; // type is Option<$0>
+ let mut v = None; // type is Option<$1>
+ let mut x = None; // type is Option<$2>
+
+ Foo::foo(x.unwrap(),u,v); // register <$2 as Foo<$0, $1>>
+ u = v; // mark $0 and $1 in a subtype relationship
+ //~^ ERROR mismatched types
+ x = Some(()); // set $2 = (), allowing impl selection
+ // to proceed for <() as Foo<$0, $1>> = impl A.
+ // kaboom, this *used* to trigge an ICE
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-30225.rs:31:9
+ |
+LL | u = v; // mark $0 and $1 in a subtype relationship
+ | ^ expected struct `A`, found struct `B`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![crate_type="lib"]
+
+
+pub trait A {
+ fn a(&self) {}
+}
+impl A for () {}
--- /dev/null
+#![crate_type="lib"]
+
+pub extern crate xcrate_issue_43189_a;
--- /dev/null
+#![crate_type="lib"]
+
+pub extern crate core;
--- /dev/null
+// edition:2018
+#![crate_type="lib"]
+#![crate_name="xcrate_issue_61711_b"]
+pub struct Struct;
+pub use crate as alias;
--- /dev/null
+// Issue 46112: An extern crate pub re-exporting libcore was causing
+// paths rooted from `std` to be misrendered in the diagnostic output.
+
+// ignore-windows
+// aux-build:xcrate-issue-43189-a.rs
+// aux-build:xcrate-issue-43189-b.rs
+
+extern crate xcrate_issue_43189_b;
+fn main() {
+ ().a();
+ //~^ ERROR no method named `a` found
+}
--- /dev/null
+error[E0599]: no method named `a` found for unit type `()` in the current scope
+ --> $DIR/issue-43189.rs:10:8
+ |
+LL | ().a();
+ | ^ method not found in `()`
+ |
+ ::: $DIR/auxiliary/xcrate-issue-43189-a.rs:5:8
+ |
+LL | fn a(&self) {}
+ | - the method is available for `()` here
+ |
+ = help: items from traits can only be used if the trait is in scope
+help: the following trait is implemented but not in scope; perhaps add a `use` for it:
+ |
+LL | use xcrate_issue_43189_b::xcrate_issue_43189_a::A;
+ |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
--- /dev/null
+// Issue 46112: An extern crate pub re-exporting libcore was causing
+// paths rooted from `std` to be misrendered in the diagnostic output.
+
+// ignore-windows
+// aux-build:xcrate-issue-46112-rexport-core.rs
+
+extern crate xcrate_issue_46112_rexport_core;
+fn test(r: Result<Option<()>, &'static str>) { }
+fn main() { test(Ok(())); }
+//~^ mismatched types
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-46112.rs:9:21
+ |
+LL | fn main() { test(Ok(())); }
+ | ^^
+ | |
+ | expected enum `Option`, found `()`
+ | help: try using a variant of the expected enum: `Some(())`
+ |
+ = note: expected enum `Option<()>`
+ found unit type `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// Issue 61711: A crate pub re-exporting `crate` was causing an
+// infinite loop.
+
+// edition:2018
+// aux-build:xcrate-issue-61711-b.rs
+// compile-flags:--extern xcrate_issue_61711_b
+
+// build-pass
+
+fn f<F: Fn(xcrate_issue_61711_b::Struct)>(_: F) { }
+fn main() { }
--- /dev/null
+fn main() {
+ 0u8.as_ref(); //~ ERROR no method named `as_ref` found for type `u8` in the current scope
+}
--- /dev/null
+error[E0599]: no method named `as_ref` found for type `u8` in the current scope
+ --> $DIR/issue-89806.rs:2:9
+ |
+LL | 0u8.as_ref();
+ | ^^^^^^ method not found in `u8`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
--- /dev/null
+use std::path::{Path, PathBuf};
+
+fn func(path: impl Into<PathBuf>, code: impl Into<String>) {}
+
+fn main() {
+ func(Path::new("hello").to_path_buf().to_string_lossy(), "world")
+ //~^ ERROR [E0277]
+}
--- /dev/null
+error[E0277]: the trait bound `PathBuf: From<Cow<'_, str>>` is not satisfied
+ --> $DIR/issue-90101.rs:6:10
+ |
+LL | func(Path::new("hello").to_path_buf().to_string_lossy(), "world")
+ | ---- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<Cow<'_, str>>` is not implemented for `PathBuf`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the following implementations were found:
+ <PathBuf as From<&T>>
+ <PathBuf as From<Box<Path>>>
+ <PathBuf as From<Cow<'a, Path>>>
+ <PathBuf as From<OsString>>
+ <PathBuf as From<String>>
+ = note: required because of the requirements on the impl of `Into<PathBuf>` for `Cow<'_, str>`
+note: required by a bound in `func`
+ --> $DIR/issue-90101.rs:3:20
+ |
+LL | fn func(path: impl Into<PathBuf>, code: impl Into<String>) {}
+ | ^^^^^^^^^^^^^ required by this bound in `func`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+fn copy<R: Unpin, W>(_: R, _: W) {}
+
+fn f<T>(r: T) {
+ let w = ();
+ copy(r, w);
+ //~^ ERROR [E0277]
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: `T` cannot be unpinned
+ --> $DIR/issue-90164.rs:5:10
+ |
+LL | copy(r, w);
+ | ---- ^ the trait `Unpin` is not implemented for `T`
+ | |
+ | required by a bound introduced by this call
+ |
+ = note: consider using `Box::pin`
+note: required by a bound in `copy`
+ --> $DIR/issue-90164.rs:1:12
+ |
+LL | fn copy<R: Unpin, W>(_: R, _: W) {}
+ | ^^^^^ required by this bound in `copy`
+help: consider restricting type parameter `T`
+ |
+LL | fn f<T: std::marker::Unpin>(r: T) {
+ | ++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// edition:2021
+
+mod m {
+ pub struct S { foo: i32 }
+ impl S {
+ pub fn foo(&self) -> i32 { 42 }
+ }
+}
+
+fn bar(s: &m::S) {
+ || s.foo() + s.foo; //~ ERROR E0616
+}
+
+fn main() {}
--- /dev/null
+error[E0616]: field `foo` of struct `S` is private
+ --> $DIR/issue-90483-inaccessible-field-adjustment.rs:11:18
+ |
+LL | || s.foo() + s.foo;
+ | ^^^ private field
+ |
+help: a method `foo` also exists, call it with parentheses
+ |
+LL | || s.foo() + s.foo();
+ | ++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0616`.
| ^^^^ required by this bound in `test`
error[E0277]: `UnsafeCell<NoSync>` cannot be shared between threads safely
- --> $DIR/typeck-unsafe-always-share.rs:27:5
+ --> $DIR/typeck-unsafe-always-share.rs:27:10
|
LL | test(ms);
- | ^^^^ `UnsafeCell<NoSync>` cannot be shared between threads safely
+ | ---- ^^ `UnsafeCell<NoSync>` cannot be shared between threads safely
+ | |
+ | required by a bound introduced by this call
|
= help: within `MySync<NoSync>`, the trait `Sync` is not implemented for `UnsafeCell<NoSync>`
note: required because it appears within the type `MySync<NoSync>`
+++ /dev/null
-// run-pass
-
-pub fn main() {
- let a = 1;
- let a_neg: i8 = -a;
- println!("{}", a_neg);
-
- let b = 1;
- let b_neg: i16 = -b;
- println!("{}", b_neg);
-
- let c = 1;
- let c_neg: i32 = -c;
- println!("{}", c_neg);
-
- let d = 1;
- let d_neg: i64 = -d;
- println!("{}", d_neg);
-
- let e = 1;
- let e_neg: isize = -e;
- println!("{}", e_neg);
-}
--- /dev/null
+// run-pass
+// Tests multiple free variables being passed by value into an unboxed
+// once closure as an optimization by codegen. This used to hit an
+// incorrect assert.
+
+fn main() {
+ let x = 2u8;
+ let y = 3u8;
+ assert_eq!((move || x + y)(), 5);
+}
| ------ ------ ^ ...but data from `y` flows into `x` here
| |
| these two types are declared with different lifetimes...
+ |
+ = note: each elided lifetime in input position becomes a distinct lifetime
+help: consider introducing a named lifetime parameter
+ |
+LL | fn foo<'a>(x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
+ | ++++ ~~ ~~
error: aborting due to previous error
fn main() {
foo::Foo(());
- foo::std_io::stdout();
+ let _ = foo::std_io::stdout();
foo::local_io(());
- io::stdout();
- bar::io::stdout();
+ let _ = io::stdout();
+ let _ = bar::io::stdout();
bar::std();
bar::std!();
// scope is allowed, when both resolve to the same definition.
use std::io;
use io::stdout;
- stdout();
+ let _ = stdout();
}
}
fn main() {
Foo(());
- std_io::stdout();
+ let _ = std_io::stdout();
local_io(());
{
// scope is allowed, when both resolve to the same definition.
use ::std::io as std_io;
use std_io::stdout;
- stdout();
+ let _ = stdout();
}
}
fn main() {
foo::Foo(());
- foo::std_io::stdout();
+ let _ = foo::std_io::stdout();
foo::local_io(());
- io::stdout();
- bar::io::stdout();
+ let _ = io::stdout();
+ let _ = bar::io::stdout();
}
fn main() {
Foo(());
- std_io::stdout();
+ let _ = std_io::stdout();
local_io(());
}
+++ /dev/null
-// edition:2018
-
-#![deny(unused_extern_crates)]
-#![feature(test, rustc_private, crate_visibility_modifier)]
-
-extern crate libc;
-//~^ ERROR unused extern crate
-//~| HELP remove
-extern crate libc as x;
-//~^ ERROR unused extern crate
-//~| HELP remove
-
-extern crate proc_macro;
-
-#[macro_use]
-extern crate test;
-
-pub extern crate test as y;
-
-pub extern crate alloc;
-
-pub(crate) extern crate alloc as a;
-
-crate extern crate alloc as b;
-
-mod foo {
- pub(in crate::foo) extern crate alloc as c;
-
- pub(super) extern crate alloc as d;
-
- extern crate libc;
- //~^ ERROR unused extern crate
- //~| HELP remove
-
- extern crate libc as x;
- //~^ ERROR unused extern crate
- //~| HELP remove
-
- pub extern crate test;
-
- pub extern crate test as y;
-
- mod bar {
- extern crate libc;
- //~^ ERROR unused extern crate
- //~| HELP remove
-
- extern crate libc as x;
- //~^ ERROR unused extern crate
- //~| HELP remove
-
- pub(in crate::foo::bar) extern crate alloc as e;
-
- fn dummy() {
- e::string::String::new();
- }
- }
-
- fn dummy() {
- c::string::String::new();
- d::string::String::new();
- }
-}
-
-
-fn main() {
- a::string::String::new();
- b::string::String::new();
-
- proc_macro::TokenStream::new();
-}
+++ /dev/null
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:6:1
- |
-LL | extern crate libc;
- | ^^^^^^^^^^^^^^^^^^ help: remove it
- |
-note: the lint level is defined here
- --> $DIR/unnecessary-extern-crate.rs:3:9
- |
-LL | #![deny(unused_extern_crates)]
- | ^^^^^^^^^^^^^^^^^^^^
-
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:9:1
- |
-LL | extern crate libc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:31:5
- |
-LL | extern crate libc;
- | ^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:35:5
- |
-LL | extern crate libc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:44:9
- |
-LL | extern crate libc;
- | ^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: unused extern crate
- --> $DIR/unnecessary-extern-crate.rs:48:9
- |
-LL | extern crate libc as x;
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
-
-error: aborting due to 6 previous errors
-
+++ /dev/null
-// build-pass (FIXME(62277): could be check-pass?)
-
-#![feature(rustc_attrs)]
-
-#[rustc_dummy(a b c d)]
-#[rustc_dummy[a b c d]]
-#[rustc_dummy{a b c d}]
-fn main() {}
| |
| required by a bound introduced by this call
|
- = help: the trait `Sized` is not implemented for `[u8]`
+ = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]`
note: required because it appears within the type `A<[u8]>`
--> $DIR/unsized-exprs.rs:3:8
|
--- /dev/null
+pub struct X([u8]);
+
+pub static Y: &'static X = {
+ const Y: &'static [u8] = b"";
+ &X(*Y)
+ //~^ ERROR E0277
+};
+
+fn main() {}
--- /dev/null
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+ --> $DIR/issue-30355.rs:5:8
+ |
+LL | &X(*Y)
+ | ^^ doesn't have a size known at compile-time
+ |
+ = help: the trait `Sized` is not implemented for `[u8]`
+ = note: all function arguments must have a statically known size
+ = help: unsized fn params are gated as an unstable feature
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
-#![feature(relaxed_struct_unsize)]
// run-pass
// Test that we allow unsizing even if there is an unchanged param in the
// field getting unsized.
// --extern-location with a raw reference
// aux-crate:bar=bar.rs
-// compile-flags:--extern-location bar
+// compile-flags:--extern-location bar -Zunstable-options
#![warn(unused_crate_dependencies)]
-#![feature(use_nested_groups)]
#![allow(dead_code)]
#![deny(unused_imports)]
error: unused imports: `*`, `Foo`, `baz::{}`, `foobar::*`
- --> $DIR/use-nested-groups-unused-imports.rs:16:11
+ --> $DIR/use-nested-groups-unused-imports.rs:15:11
|
LL | use foo::{Foo, bar::{baz::{}, foobar::*}, *};
| ^^^ ^^^^^^^ ^^^^^^^^^ ^
|
note: the lint level is defined here
- --> $DIR/use-nested-groups-unused-imports.rs:3:9
+ --> $DIR/use-nested-groups-unused-imports.rs:2:9
|
LL | #![deny(unused_imports)]
| ^^^^^^^^^^^^^^
error: unused import: `*`
- --> $DIR/use-nested-groups-unused-imports.rs:18:24
+ --> $DIR/use-nested-groups-unused-imports.rs:17:24
|
LL | use foo::bar::baz::{*, *};
| ^
error: unused import: `foo::{}`
- --> $DIR/use-nested-groups-unused-imports.rs:20:5
+ --> $DIR/use-nested-groups-unused-imports.rs:19:5
|
LL | use foo::{};
| ^^^^^^^
+++ /dev/null
-// run-pass
-
-#![allow(dead_code)]
-// compile-flags:-D improper-ctypes
-
-// pretty-expanded FIXME #23616
-#![allow(improper_ctypes)]
-
-mod libc {
- extern "C" {
- pub fn malloc(size: isize) -> *const u8;
- }
-}
-
-pub fn main() {}
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "illumos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
- target_os = "vxworks",
- target_os = "solaris"))]
+ target_os = "solaris",
+ target_os = "vxworks"))]
pub fn main() { }
+++ /dev/null
-// run-pass
-
-use std::thread;
-
-pub fn main() {
- let mut i: isize = 0;
- while i < 100 { i = i + 1; println!("{}", i); thread::yield_now(); }
-}
#[derive(Debug, serde::Deserialize)]
struct ManifestTargetPackage {
- available: bool,
url: Option<String>,
hash: Option<String>,
xz_url: Option<String>,
-Subproject commit 7fbbf4e8f23e3c24b8afff541dcb17e53eb5ff88
+Subproject commit 2e2a16e983f597da62bc132eb191bc3276d4b1bb
+++ /dev/null
-[alias]
-uitest = "test --test compile-test"
-dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
-lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- "
-collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored"
-
-[build]
-# -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests
-rustflags = ["-Zunstable-options", "-Zbinary-dep-depinfo"]
-target-dir = "target"
--- /dev/null
+[alias]
+uitest = "test --test compile-test"
+dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
+lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- "
+collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored"
+
+[build]
+# -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests
+rustflags = ["-Zunstable-options", "-Zbinary-dep-depinfo"]
+target-dir = "target"
if [[ -n $TAG_NAME ]]; then
echo "Save the doc for the current tag ($TAG_NAME) and point stable/ to it"
cp -Tr out/master "out/$TAG_NAME"
- ln -sf "$TAG_NAME" out/stable
+ rm -f out/stable
+ ln -s "$TAG_NAME" out/stable
fi
if [[ $BETA = "true" ]]; then
## Unreleased / In Rust Nightly
-[7bfc26e...master](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...master)
+[b7f3f7f...master](https://github.com/rust-lang/rust-clippy/compare/b7f3f7f...master)
+
+## Rust 1.57
+
+Current beta, release 2021-12-02
+
+[7bfc26e...b7f3f7f](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...b7f3f7f)
+
+### New Lints
+
+* [`negative_feature_names`]
+ [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
+* [`redundant_feature_names`]
+ [#7539](https://github.com/rust-lang/rust-clippy/pull/7539)
+* [`mod_module_files`]
+ [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
+* [`self_named_module_files`]
+ [#7543](https://github.com/rust-lang/rust-clippy/pull/7543)
+* [`manual_split_once`]
+ [#7565](https://github.com/rust-lang/rust-clippy/pull/7565)
+* [`derivable_impls`]
+ [#7570](https://github.com/rust-lang/rust-clippy/pull/7570)
+* [`needless_option_as_deref`]
+ [#7596](https://github.com/rust-lang/rust-clippy/pull/7596)
+* [`iter_not_returning_iterator`]
+ [#7610](https://github.com/rust-lang/rust-clippy/pull/7610)
+* [`same_name_method`]
+ [#7653](https://github.com/rust-lang/rust-clippy/pull/7653)
+* [`manual_assert`] [#7669](https://github.com/rust-lang/rust-clippy/pull/7669)
+* [`non_send_fields_in_send_ty`]
+ [#7709](https://github.com/rust-lang/rust-clippy/pull/7709)
+* [`equatable_if_let`]
+ [#7762](https://github.com/rust-lang/rust-clippy/pull/7762)
+
+### Moves and Deprecations
+
+* Move [`shadow_unrelated`] to `restriction`
+ [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
+* Move [`option_if_let_else`] to `nursery`
+ [#7568](https://github.com/rust-lang/rust-clippy/pull/7568)
+* Move [`branches_sharing_code`] to `nursery`
+ [#7595](https://github.com/rust-lang/rust-clippy/pull/7595)
+* Rename `if_let_some_result` to [`match_result_ok`] which now also handles
+ `while let` cases [#7608](https://github.com/rust-lang/rust-clippy/pull/7608)
+* Move [`many_single_char_names`] to `pedantic`
+ [#7671](https://github.com/rust-lang/rust-clippy/pull/7671)
+* Move [`float_cmp`] to `pedantic`
+ [#7692](https://github.com/rust-lang/rust-clippy/pull/7692)
+* Rename `box_vec` to [`box_collection`] and lint on more general cases
+ [#7693](https://github.com/rust-lang/rust-clippy/pull/7693)
+* Uplift `invalid_atomic_ordering` to rustc
+ [rust-lang/rust#84039](https://github.com/rust-lang/rust/pull/84039)
+
+### Enhancements
+
+* Rewrite the `shadow*` lints, so that they find a lot more shadows and are not
+ limited to certain patterns
+ [#7338](https://github.com/rust-lang/rust-clippy/pull/7338)
+* The `avoid-breaking-exported-api` configuration now also works for
+ [`box_collection`], [`redundant_allocation`], [`rc_buffer`], [`vec_box`],
+ [`option_option`], [`linkedlist`], [`rc_mutex`]
+ [#7560](https://github.com/rust-lang/rust-clippy/pull/7560)
+* [`unnecessary_unwrap`]: Now also checks for `expect`s
+ [#7584](https://github.com/rust-lang/rust-clippy/pull/7584)
+* [`disallowed_method`]: Allow adding a reason that will be displayed with the
+ lint message
+ [#7621](https://github.com/rust-lang/rust-clippy/pull/7621)
+* [`approx_constant`]: Now checks the MSRV for `LOG10_2` and `LOG2_10`
+ [#7629](https://github.com/rust-lang/rust-clippy/pull/7629)
+* [`approx_constant`]: Add `TAU`
+ [#7642](https://github.com/rust-lang/rust-clippy/pull/7642)
+* [`needless_borrow`]: Now also lints on needless mutable borrows
+ [#7657](https://github.com/rust-lang/rust-clippy/pull/7657)
+* [`missing_safety_doc`]: Now also lints on unsafe traits
+ [#7734](https://github.com/rust-lang/rust-clippy/pull/7734)
+
+### False Positive Fixes
+
+* [`manual_map`]: No longer lints when the option is borrowed in the match and
+ also consumed in the arm
+ [#7531](https://github.com/rust-lang/rust-clippy/pull/7531)
+* [`filter_next`]: No longer lints if `filter` method is not the
+ `Iterator::filter` method
+ [#7562](https://github.com/rust-lang/rust-clippy/pull/7562)
+* [`manual_flatten`]: No longer lints if expression is used after `if let`
+ [#7566](https://github.com/rust-lang/rust-clippy/pull/7566)
+* [`option_if_let_else`]: Multiple fixes
+ [#7573](https://github.com/rust-lang/rust-clippy/pull/7573)
+ * `break` and `continue` statements local to the would-be closure are
+ allowed
+ * Don't lint in const contexts
+ * Don't lint when yield expressions are used
+ * Don't lint when the captures made by the would-be closure conflict with
+ the other branch
+ * Don't lint when a field of a local is used when the type could be
+ potentially moved from
+ * In some cases, don't lint when scrutinee expression conflicts with the
+ captures of the would-be closure
+* [`redundant_allocation`]: No longer lints on `Box<Box<dyn T>>` which replaces
+ wide pointers with thin pointers
+ [#7592](https://github.com/rust-lang/rust-clippy/pull/7592)
+* [`bool_assert_comparison`]: No longer lints on types that do not implement the
+ `Not` trait with `Output = bool`
+ [#7605](https://github.com/rust-lang/rust-clippy/pull/7605)
+* [`mut_range_bound`]: No longer lints on range bound mutations, that are
+ immediately followed by a `break;`
+ [#7607](https://github.com/rust-lang/rust-clippy/pull/7607)
+* [`mutable_key_type`]: Improve accuracy and document remaining false positives
+ and false negatives
+ [#7640](https://github.com/rust-lang/rust-clippy/pull/7640)
+* [`redundant_closure`]: Rewrite the lint to fix various false positives and
+ false negatives [#7661](https://github.com/rust-lang/rust-clippy/pull/7661)
+* [`large_enum_variant`]: No longer wrongly identifies the second largest
+ variant [#7677](https://github.com/rust-lang/rust-clippy/pull/7677)
+* [`needless_return`]: No longer lints on let-else expressions
+ [#7685](https://github.com/rust-lang/rust-clippy/pull/7685)
+* [`suspicious_else_formatting`]: No longer lints in proc-macros
+ [#7707](https://github.com/rust-lang/rust-clippy/pull/7707)
+* [`excessive_precision`]: No longer lints when in some cases the float was
+ already written in the shortest form
+ [#7722](https://github.com/rust-lang/rust-clippy/pull/7722)
+* [`doc_markdown`]: No longer lints on intra-doc links
+ [#7772](https://github.com/rust-lang/rust-clippy/pull/7772)
+
+### Suggestion Fixes/Improvements
+
+* [`unnecessary_operation`]: Recommend using an `assert!` instead of using a
+ function call in an indexing operation
+ [#7453](https://github.com/rust-lang/rust-clippy/pull/7453)
+* [`manual_split_once`]: Produce semantically equivalent suggestion when
+ `rsplitn` is used [#7663](https://github.com/rust-lang/rust-clippy/pull/7663)
+* [`while_let_on_iterator`]: Produce correct suggestion when using `&mut`
+ [#7690](https://github.com/rust-lang/rust-clippy/pull/7690)
+* [`manual_assert`]: No better handles complex conditions
+ [#7741](https://github.com/rust-lang/rust-clippy/pull/7741)
+* Correctly handle signs in exponents in numeric literals lints
+ [#7747](https://github.com/rust-lang/rust-clippy/pull/7747)
+* [`suspicious_map`]: Now also suggests to use `inspect` as an alternative
+ [#7770](https://github.com/rust-lang/rust-clippy/pull/7770)
+* Drop exponent from suggestion if it is 0 in numeric literals lints
+ [#7774](https://github.com/rust-lang/rust-clippy/pull/7774)
+
+### ICE Fixes
+
+* [`implicit_hasher`]
+ [#7761](https://github.com/rust-lang/rust-clippy/pull/7761)
+
+### Others
+
+* Clippy now uses the 2021
+ [Edition!](https://www.youtube.com/watch?v=q0aNduqb2Ro)
+ [#7664](https://github.com/rust-lang/rust-clippy/pull/7664)
## Rust 1.56
-Current beta, release 2021-10-21
+Current stable, released 2021-10-21
[74d1561...7bfc26e](https://github.com/rust-lang/rust-clippy/compare/74d1561...7bfc26e)
* [`unnested_or_patterns`]: Removed `or_patterns` feature gate in the code
example [#7507](https://github.com/rust-lang/rust-clippy/pull/7507)
-### New Lints
-
-* Renamed Lint: `if_let_some_result` is now called [`match_result_ok`]. Now also handles `while let` case.
-
## Rust 1.55
-Current stable, released 2021-09-09
+Released 2021-09-09
[3ae8faf...74d1561](https://github.com/rust-lang/rust-clippy/compare/3ae8faf...74d1561)
[`if_let_redundant_pattern_matching`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_let_redundant_pattern_matching
[`if_not_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_not_else
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
-[`if_then_panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_panic
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
[`implicit_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#implicit_clone
[`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
+[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
[`self_named_constructors`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_constructors
[`self_named_module_files`]: https://rust-lang.github.io/rust-clippy/master/index.html#self_named_module_files
[`semicolon_if_nothing_returned`]: https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_if_nothing_returned
+[`separated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#separated_literal_suffix
[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse
[`shadow_reuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_reuse
[`shadow_same`]: https://rust-lang.github.io/rust-clippy/master/index.html#shadow_same
[`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars
[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes
[`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes
+[`string_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_slice
[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
[`uninit_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_vec
[`unit_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_arg
[`unit_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_cmp
+[`unit_hash`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_hash
[`unit_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
2. Checkout the commit from the latest available nightly. You can get it using `rustup check`.
3. Sync the changes to the rust-copy of Clippy to your Clippy fork:
```bash
- # Make sure to change `your-github-name` to your github name in the following command
+ # Make sure to change `your-github-name` to your github name in the following command. Also be
+ # sure to either use a net-new branch, e.g. `sync-from-rust`, or delete the branch beforehand
+ # because changes cannot be fast forwarded
git subtree push -P src/tools/clippy git@github.com:your-github-name/rust-clippy sync-from-rust
```
[dependencies]
clippy_lints = { version = "0.1", path = "clippy_lints" }
-semver = "0.11"
+semver = "1.0"
rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
tempfile = { version = "3.2", optional = true }
[dev-dependencies]
-cargo_metadata = "0.12"
-compiletest_rs = { version = "0.7", features = ["tmp"] }
+cargo_metadata = "0.14"
+compiletest_rs = { version = "0.7.1", features = ["tmp"] }
tester = "0.9"
regex = "1.5"
# This is used by the `collect-metadata` alias.
};
create_lint(&lint, msrv).context("Unable to create lint implementation")?;
- create_test(&lint).context("Unable to create a test for the new lint")
+ create_test(&lint).context("Unable to create a test for the new lint")?;
+ add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")
}
fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
}
}
+fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
+ let path = "clippy_lints/src/lib.rs";
+ let mut lib_rs = fs::read_to_string(path).context("reading")?;
+
+ let comment_start = lib_rs.find("// add lints here,").expect("Couldn't find comment");
+
+ let new_lint = if enable_msrv {
+ format!(
+ "store.register_{lint_pass}_pass(move || Box::new({module_name}::{camel_name}::new(msrv)));\n ",
+ lint_pass = lint.pass,
+ module_name = lint.name,
+ camel_name = to_camel_case(lint.name),
+ )
+ } else {
+ format!(
+ "store.register_{lint_pass}_pass(|| Box::new({module_name}::{camel_name}));\n ",
+ lint_pass = lint.pass,
+ module_name = lint.name,
+ camel_name = to_camel_case(lint.name),
+ )
+ };
+
+ lib_rs.insert_str(comment_start, &new_lint);
+
+ fs::write(path, lib_rs).context("writing")
+}
+
fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> {
fn inner(path: &Path, contents: &[u8]) -> io::Result<()> {
OpenOptions::new()
};
let lint_name = lint.name;
- let pass_name = lint.pass;
let category = lint.category;
let name_camel = to_camel_case(lint.name);
let name_upper = lint_name.to_uppercase();
extract_msrv_attr!({context_import});
}}
- // TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
- // e.g. store.register_{pass_name}_pass(move || Box::new({module_name}::{name_camel}::new(msrv)));
// TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
// TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
// TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
"},
pass_type = pass_type,
pass_lifetimes = pass_lifetimes,
- pass_name = pass_name,
name_upper = name_upper,
name_camel = name_camel,
- module_name = lint_name,
context_import = context_import,
)
} else {
declare_lint_pass!({name_camel} => [{name_upper}]);
impl {pass_type}{pass_lifetimes} for {name_camel} {{}}
- //
- // TODO: Register the lint pass in `clippy_lints/src/lib.rs`,
- // e.g. store.register_{pass_name}_pass(|| Box::new({module_name}::{name_camel}));
"},
pass_type = pass_type,
pass_lifetimes = pass_lifetimes,
- pass_name = pass_name,
name_upper = name_upper,
name_camel = name_camel,
- module_name = lint_name,
)
});
edition = "2021"
[dependencies]
-cargo_metadata = "0.12"
+cargo_metadata = "0.14"
clippy_utils = { path = "../clippy_utils" }
if_chain = "1.0"
itertools = "0.10"
toml = "0.5"
unicode-normalization = "0.1"
unicode-script = { version = "0.5", default-features = false }
-semver = "0.11"
+semver = "1.0"
rustc-semver = "1.1"
# NOTE: cargo requires serde feat in its url dep
# see <https://github.com/rust-lang/rust/pull/63587#issuecomment-522343864>
+use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
+use clippy_utils::expr_or_init;
use clippy_utils::ty::is_isize_or_usize;
-use rustc_hir::Expr;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, FloatTy, Ty};
use super::{utils, CAST_POSSIBLE_TRUNCATION};
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> {
+ if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) {
+ Some(c)
+ } else {
+ None
+ }
+}
+
+fn get_constant_bits(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u64> {
+ constant_int(cx, expr).map(|c| u64::from(128 - c.leading_zeros()))
+}
+
+fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: bool) -> u64 {
+ match expr_or_init(cx, expr).kind {
+ ExprKind::Cast(inner, _) => apply_reductions(cx, nbits, inner, signed),
+ ExprKind::Block(block, _) => block.expr.map_or(nbits, |e| apply_reductions(cx, nbits, e, signed)),
+ ExprKind::Binary(op, left, right) => match op.node {
+ BinOpKind::Div => {
+ apply_reductions(cx, nbits, left, signed)
+ - (if signed {
+ 0 // let's be conservative here
+ } else {
+ // by dividing by 1, we remove 0 bits, etc.
+ get_constant_bits(cx, right).map_or(0, |b| b.saturating_sub(1))
+ })
+ },
+ BinOpKind::Rem | BinOpKind::BitAnd => get_constant_bits(cx, right)
+ .unwrap_or(u64::max_value())
+ .min(apply_reductions(cx, nbits, left, signed)),
+ BinOpKind::Shr => {
+ apply_reductions(cx, nbits, left, signed)
+ - constant_int(cx, right).map_or(0, |s| u64::try_from(s).expect("shift too high"))
+ },
+ _ => nbits,
+ },
+ ExprKind::MethodCall(method, _, [left, right], _) => {
+ if signed {
+ return nbits;
+ }
+ let max_bits = if method.ident.as_str() == "min" {
+ get_constant_bits(cx, right)
+ } else {
+ None
+ };
+ apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::max_value()))
+ },
+ ExprKind::MethodCall(method, _, [_, lo, hi], _) => {
+ if method.ident.as_str() == "clamp" {
+ //FIXME: make this a diagnostic item
+ if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
+ return lo_bits.max(hi_bits);
+ }
+ }
+ nbits
+ },
+ ExprKind::MethodCall(method, _, [_value], _) => {
+ if method.ident.name.as_str() == "signum" {
+ 0 // do not lint if cast comes from a `signum` function
+ } else {
+ nbits
+ }
+ },
+ _ => nbits,
+ }
+}
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
let msg = match (cast_from.is_integral(), cast_to.is_integral()) {
(true, true) => {
- let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
+ let from_nbits = apply_reductions(
+ cx,
+ utils::int_ty_to_nbits(cast_from, cx.tcx),
+ cast_expr,
+ cast_from.is_signed(),
+ );
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) {
- cast_possible_truncation::check(cx, expr, cast_from, cast_to);
+ cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
cast_possible_wrap::check(cx, expr, cast_from, cast_to);
cast_precision_loss::check(cx, expr, cast_from, cast_to);
cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to);
+// NOTE: if you add a deprecated lint in this file, please add a corresponding test in
+// tests/ui/deprecated.rs
+
/// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This
/// enables the simple extraction of the metadata without changing the current deprecation
/// declaration.
target_mut,
},
));
- }
+ },
_ => (),
}
},
use clippy_utils::attrs::is_doc_hidden;
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note};
-use clippy_utils::source::first_line_of_span;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_sugg};
+use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty};
use if_chain::if_chain;
use itertools::Itertools;
-use rustc_ast::ast::{Async, AttrKind, Attribute, FnKind, FnRetTy, ItemKind};
+use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
use rustc_ast::token::CommentKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::sync::Lrc;
use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::Handler;
+use rustc_errors::{Applicability, Handler};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
/// content are not linted.
///
/// In addition, when writing documentation comments, including `[]` brackets
- /// inside a link text would trip the parser. Therfore, documenting link with
+ /// inside a link text would trip the parser. Therefore, documenting link with
/// `[`SmallVec<[T; INLINE_CAPACITY]>`]` and then [`SmallVec<[T; INLINE_CAPACITY]>`]: SmallVec
/// would fail.
///
// text "http://example.com" by pulldown-cmark
continue;
}
- headers.safety |= in_heading && text.trim() == "Safety";
- headers.errors |= in_heading && text.trim() == "Errors";
- headers.panics |= in_heading && text.trim() == "Panics";
+ let trimmed_text = text.trim();
+ headers.safety |= in_heading && trimmed_text == "Safety";
+ headers.safety |= in_heading && trimmed_text == "Implementation safety";
+ headers.safety |= in_heading && trimmed_text == "Implementation Safety";
+ headers.errors |= in_heading && trimmed_text == "Errors";
+ headers.panics |= in_heading && trimmed_text == "Panics";
if in_code {
if is_rust {
let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
| ItemKind::ExternCrate(..)
| ItemKind::ForeignMod(..) => return false,
// We found a main function ...
- ItemKind::Fn(box FnKind(_, sig, _, Some(block))) if item.ident.name == sym::main => {
+ ItemKind::Fn(box Fn { sig, body: Some(block), .. }) if item.ident.name == sym::main => {
let is_async = matches!(sig.header.asyncness, Async::Yes { .. });
let returns_nothing = match &sig.decl.output {
FnRetTy::Default(..) => true,
for word in text.split(|c: char| c.is_whitespace() || c == '\'') {
// Trim punctuation as in `some comment (see foo::bar).`
// ^^
- // Or even as in `_foo bar_` which is emphasized.
- let word = word.trim_matches(|c: char| !c.is_alphanumeric());
+ // Or even as in `_foo bar_` which is emphasized. Also preserve `::` as a prefix/suffix.
+ let mut word = word.trim_matches(|c: char| !c.is_alphanumeric() && c != ':');
- if valid_idents.contains(word) {
+ // Remove leading or trailing single `:` which may be part of a sentence.
+ if word.starts_with(':') && !word.starts_with("::") {
+ word = word.trim_start_matches(':');
+ }
+ if word.ends_with(':') && !word.ends_with("::") {
+ word = word.trim_end_matches(':');
+ }
+
+ if valid_idents.contains(word) || word.chars().all(|c| c == ':') {
continue;
}
}
}
- // We assume that mixed-case words are not meant to be put inside bacticks. (Issue #2343)
+ // We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
if has_underscore(word) && has_hyphen(word) {
return;
}
if has_underscore(word) || word.contains("::") || is_camel_case(word) {
- span_lint(
+ let mut applicability = Applicability::MachineApplicable;
+
+ span_lint_and_sugg(
cx,
DOC_MARKDOWN,
span,
- &format!("you should put `{}` between ticks in the documentation", word),
+ "item in documentation is missing backticks",
+ "try",
+ format!("`{}`", snippet_with_applicability(cx, span, "..", &mut applicability)),
+ applicability,
);
}
}
// check for `unwrap`
if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
- let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
- if is_type_diagnostic_item(self.cx, reciever_ty, sym::Option)
- || is_type_diagnostic_item(self.cx, reciever_ty, sym::Result)
+ let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
+ if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
+ || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
{
self.panic_span = Some(expr.span);
}
ExprKind::MethodCall(
_,
_,
- [map, Expr {
- kind: ExprKind::AddrOf(_, _, key),
- span: key_span,
- ..
- }],
+ [
+ map,
+ Expr {
+ kind: ExprKind::AddrOf(_, _, key),
+ span: key_span,
+ ..
+ },
+ ],
_,
) if key_span.ctxt() == expr.span.ctxt() => {
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
//! lint on enum variants that are prefixed or suffixed by the same characters
-use clippy_utils::camel_case;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::source::is_present_in_source;
+use clippy_utils::str_utils::{self, count_match_end, count_match_start};
use rustc_hir::{EnumDef, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
MODULE_INCEPTION
]);
-/// Returns the number of chars that match from the start
-#[must_use]
-fn partial_match(pre: &str, name: &str) -> usize {
- let mut name_iter = name.chars();
- let _ = name_iter.next_back(); // make sure the name is never fully matched
- pre.chars().zip(name_iter).take_while(|&(l, r)| l == r).count()
-}
-
-/// Returns the number of chars that match from the end
-#[must_use]
-fn partial_rmatch(post: &str, name: &str) -> usize {
- let mut name_iter = name.chars();
- let _ = name_iter.next(); // make sure the name is never fully matched
- post.chars()
- .rev()
- .zip(name_iter.rev())
- .take_while(|&(l, r)| l == r)
- .count()
-}
-
fn check_variant(
cx: &LateContext<'_>,
threshold: u64,
}
for var in def.variants {
let name = var.ident.name.as_str();
- if partial_match(item_name, &name) == item_name_chars
+ if count_match_start(item_name, &name).char_count == item_name_chars
&& name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
&& name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
{
"variant name starts with the enum's name",
);
}
- if partial_rmatch(item_name, &name) == item_name_chars {
+ if count_match_end(item_name, &name).char_count == item_name_chars {
span_lint(
cx,
ENUM_VARIANT_NAMES,
}
}
let first = &def.variants[0].ident.name.as_str();
- let mut pre = &first[..camel_case::until(&*first)];
- let mut post = &first[camel_case::from(&*first)..];
+ let mut pre = &first[..str_utils::camel_case_until(&*first).byte_index];
+ let mut post = &first[str_utils::camel_case_start(&*first).byte_index..];
for var in def.variants {
let name = var.ident.name.as_str();
- let pre_match = partial_match(pre, &name);
+ let pre_match = count_match_start(pre, &name).byte_count;
pre = &pre[..pre_match];
- let pre_camel = camel_case::until(pre);
+ let pre_camel = str_utils::camel_case_until(pre).byte_index;
pre = &pre[..pre_camel];
while let Some((next, last)) = name[pre.len()..].chars().zip(pre.chars().rev()).next() {
if next.is_numeric() {
}
if next.is_lowercase() {
let last = pre.len() - last.len_utf8();
- let last_camel = camel_case::until(&pre[..last]);
- pre = &pre[..last_camel];
+ let last_camel = str_utils::camel_case_until(&pre[..last]);
+ pre = &pre[..last_camel.byte_index];
} else {
break;
}
}
- let post_match = partial_rmatch(post, &name);
- let post_end = post.len() - post_match;
+ let post_match = count_match_end(post, &name);
+ let post_end = post.len() - post_match.byte_count;
post = &post[post_end..];
- let post_camel = camel_case::from(post);
- post = &post[post_camel..];
+ let post_camel = str_utils::camel_case_start(post);
+ post = &post[post_camel.byte_index..];
}
let (what, value) = match (pre.is_empty(), post.is_empty()) {
(true, true) => return,
);
}
}
- if item.vis.node.is_pub() {
- let matching = partial_match(mod_camel, &item_camel);
- let rmatching = partial_rmatch(mod_camel, &item_camel);
+ // The `module_name_repetitions` lint should only trigger if the item has the module in its
+ // name. Having the same name is accepted.
+ if item.vis.node.is_pub() && item_camel.len() > mod_camel.len() {
+ let matching = count_match_start(mod_camel, &item_camel);
+ let rmatching = count_match_end(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();
let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
- if matching == nchars {
+ if matching.char_count == nchars {
match item_camel.chars().nth(nchars) {
Some(c) if is_word_beginning(c) => span_lint(
cx,
_ => (),
}
}
- if rmatching == nchars {
+ if rmatching.char_count == nchars {
span_lint(
cx,
MODULE_NAME_REPETITIONS,
}
match *cx.typeck_results().expr_adjustments(arg) {
[] => true,
- [Adjustment {
- kind: Adjust::Deref(None),
- ..
- }, Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
- ..
- }] => {
+ [
+ Adjustment {
+ kind: Adjust::Deref(None),
+ ..
+ },
+ Adjustment {
+ kind: Adjust::Borrow(AutoBorrow::Ref(_, mu2)),
+ ..
+ },
+ ] => {
// re-borrow with the same mutability is allowed
let ty = cx.typeck_results().expr_ty(arg);
matches!(*ty.kind(), ty::Ref(.., mu1) if mu1 == mu2.into())
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::in_macro;
-use rustc_ast::ast::{AssocItemKind, Extern, FnKind, FnSig, ImplKind, Item, ItemKind, TraitKind, Ty, TyKind};
+use rustc_ast::ast::{AssocItemKind, Extern, Fn, FnSig, Impl, Item, ItemKind, Trait, Ty, TyKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
);
}
},
- ItemKind::Impl(box ImplKind {
+ ItemKind::Impl(box Impl {
of_trait: None, items, ..
})
- | ItemKind::Trait(box TraitKind(.., items)) => {
+ | ItemKind::Trait(box Trait { items, .. }) => {
for item in items {
- if let AssocItemKind::Fn(box FnKind(_, fn_sig, _, _)) = &item.kind {
- self.check_fn_sig(cx, fn_sig, item.span);
+ if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
+ self.check_fn_sig(cx, sig, item.span);
}
}
},
- ItemKind::Fn(box FnKind(_, fn_sig, _, _)) => self.check_fn_sig(cx, fn_sig, item.span),
+ ItemKind::Fn(box Fn { sig, .. }) => self.check_fn_sig(cx, sig, item.span),
_ => (),
}
}
let mut applicability = Applicability::MachineApplicable;
if format_args.value_args.is_empty() {
- if_chain! {
- if let [e] = &*format_args.format_string_parts;
- if let ExprKind::Lit(lit) = &e.kind;
- if let Some(s_src) = snippet_opt(cx, lit.span);
- then {
- // Simulate macro expansion, converting {{ and }} to { and }.
- let s_expand = s_src.replace("{{", "{").replace("}}", "}");
- let sugg = format!("{}.to_string()", s_expand);
- span_useless_format(cx, call_site, sugg, applicability);
+ if format_args.format_string_parts.is_empty() {
+ span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability);
+ } else {
+ if_chain! {
+ if let [e] = &*format_args.format_string_parts;
+ if let ExprKind::Lit(lit) = &e.kind;
+ if let Some(s_src) = snippet_opt(cx, lit.span);
+ then {
+ // Simulate macro expansion, converting {{ and }} to { and }.
+ let s_expand = s_src.replace("{{", "{").replace("}}", "}");
+ let sugg = format!("{}.to_string()", s_expand);
+ span_useless_format(cx, call_site, sugg, applicability);
+ }
}
}
} else if let [value] = *format_args.value_args {
}
}
+fn span_useless_format_empty(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
+ span_lint_and_sugg(
+ cx,
+ USELESS_FORMAT,
+ span,
+ "useless use of `format!`",
+ "consider using `String::new()`",
+ sugg,
+ applicability,
+ );
+}
+
fn span_useless_format(cx: &LateContext<'_>, span: Span, sugg: String, applicability: Applicability) {
span_lint_and_sugg(
cx,
if is_future {
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
let span = decl.output.span();
- let send_result = cx.tcx.infer_ctxt().enter(|infcx| {
+ let send_errors = cx.tcx.infer_ctxt().enter(|infcx| {
let cause = traits::ObligationCause::misc(span, hir_id);
let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause);
fulfillment_cx.select_all_or_error(&infcx)
});
- if let Err(send_errors) = send_result {
+ if !send_errors.is_empty() {
span_lint_and_then(
cx,
FUTURE_NOT_SEND,
//! on the condition
use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
-use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_middle::lint::in_external_macro;
+use clippy_utils::is_else_clause;
+use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
-impl EarlyLintPass for IfNotElse {
- fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
- if in_external_macro(cx.sess, item.span) {
+impl LateLintPass<'_> for IfNotElse {
+ fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
+ // While loops will be desugared to ExprKind::If. This will cause the lint to fire.
+ // To fix this, return early if this span comes from a macro or desugaring.
+ if item.span.from_expansion() {
return;
}
- if let ExprKind::If(ref cond, _, Some(ref els)) = item.kind {
+ if let ExprKind::If(cond, _, Some(els)) = item.kind {
if let ExprKind::Block(..) = els.kind {
- match cond.kind {
+ // Disable firing the lint in "else if" expressions.
+ if is_else_clause(cx.tcx, item) {
+ return;
+ }
+
+ match cond.peel_drop_temps().kind {
ExprKind::Unary(UnOp::Not, _) => {
span_lint_and_help(
cx,
+++ /dev/null
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::PanicExpn;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_expn_of, sugg};
-use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-
-declare_clippy_lint! {
- /// ### What it does
- /// Detects `if`-then-`panic!` that can be replaced with `assert!`.
- ///
- /// ### Why is this bad?
- /// `assert!` is simpler than `if`-then-`panic!`.
- ///
- /// ### Example
- /// ```rust
- /// let sad_people: Vec<&str> = vec![];
- /// if !sad_people.is_empty() {
- /// panic!("there are sad people: {:?}", sad_people);
- /// }
- /// ```
- /// Use instead:
- /// ```rust
- /// let sad_people: Vec<&str> = vec![];
- /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
- /// ```
- pub IF_THEN_PANIC,
- style,
- "`panic!` and only a `panic!` in `if`-then statement"
-}
-
-declare_lint_pass!(IfThenPanic => [IF_THEN_PANIC]);
-
-impl LateLintPass<'_> for IfThenPanic {
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- if_chain! {
- if let Expr {
- kind: ExprKind:: If(cond, Expr {
- kind: ExprKind::Block(
- Block {
- stmts: [stmt],
- ..
- },
- _),
- ..
- }, None),
- ..
- } = &expr;
- if is_expn_of(stmt.span, "panic").is_some();
- if !matches!(cond.kind, ExprKind::Let(_, _, _));
- if let StmtKind::Semi(semi) = stmt.kind;
- if !cx.tcx.sess.source_map().is_multiline(cond.span);
-
- then {
- let span = if let Some(panic_expn) = PanicExpn::parse(semi) {
- match *panic_expn.format_args.value_args {
- [] => panic_expn.format_args.format_string_span,
- [.., last] => panic_expn.format_args.format_string_span.to(last.span),
- }
- } else {
- if_chain! {
- if let ExprKind::Block(block, _) = semi.kind;
- if let Some(init) = block.expr;
- if let ExprKind::Call(_, [format_args]) = init.kind;
-
- then {
- format_args.span
- } else {
- return
- }
- }
- };
- let mut applicability = Applicability::MachineApplicable;
- let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
- let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind {
- if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e {
- sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string()
- } else {
- format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par())
- }
- } else {
- format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par())
- };
-
- span_lint_and_sugg(
- cx,
- IF_THEN_PANIC,
- expr.span,
- "only a `panic!` in `if`-then statement",
- "try",
- format!("assert!({}, {});", cond_sugg, sugg),
- Applicability::MachineApplicable,
- );
- }
- }
- }
-}
},
_ => None,
}
- }
+ },
// case where `x + 1 <= ...` or `1 + x <= ...`
(BinOpKind::Le, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _)
if lhskind.node == BinOpKind::Add =>
},
_ => None,
}
- }
+ },
// case where `... >= y - 1` or `... >= -1 + y`
(BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
-use std::cmp::Ordering;
-
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;
+use clippy_utils::comparisons;
use clippy_utils::comparisons::Rel;
-use clippy_utils::consts::{constant, Constant};
+use clippy_utils::consts::{constant_full_int, FullInt};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet;
-use clippy_utils::{comparisons, sext};
declare_clippy_lint! {
/// ### What it does
declare_lint_pass!(InvalidUpcastComparisons => [INVALID_UPCAST_COMPARISONS]);
-#[derive(Copy, Clone, Debug, Eq)]
-enum FullInt {
- S(i128),
- U(u128),
-}
-
-impl FullInt {
- #[allow(clippy::cast_sign_loss)]
- #[must_use]
- fn cmp_s_u(s: i128, u: u128) -> Ordering {
- if s < 0 {
- Ordering::Less
- } else if u > (i128::MAX as u128) {
- Ordering::Greater
- } else {
- (s as u128).cmp(&u)
- }
- }
-}
-
-impl PartialEq for FullInt {
- #[must_use]
- fn eq(&self, other: &Self) -> bool {
- self.partial_cmp(other).expect("`partial_cmp` only returns `Some(_)`") == Ordering::Equal
- }
-}
-
-impl PartialOrd for FullInt {
- #[must_use]
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- Some(match (self, other) {
- (&Self::S(s), &Self::S(o)) => s.cmp(&o),
- (&Self::U(s), &Self::U(o)) => s.cmp(&o),
- (&Self::S(s), &Self::U(o)) => Self::cmp_s_u(s, o),
- (&Self::U(s), &Self::S(o)) => Self::cmp_s_u(o, s).reverse(),
- })
- }
-}
-
-impl Ord for FullInt {
- #[must_use]
- fn cmp(&self, other: &Self) -> Ordering {
- self.partial_cmp(other)
- .expect("`partial_cmp` for FullInt can never return `None`")
- }
-}
-
fn numeric_cast_precast_bounds<'a>(cx: &LateContext<'_>, expr: &'a Expr<'_>) -> Option<(FullInt, FullInt)> {
if let ExprKind::Cast(cast_exp, _) = expr.kind {
let pre_cast_ty = cx.typeck_results().expr_ty(cast_exp);
}
}
-fn node_as_const_fullint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<FullInt> {
- let val = constant(cx, cx.typeck_results(), expr)?.0;
- if let Constant::Int(const_int) = val {
- match *cx.typeck_results().expr_ty(expr).kind() {
- ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
- ty::Uint(_) => Some(FullInt::U(const_int)),
- _ => None,
- }
- } else {
- None
- }
-}
-
fn err_upcast_comparison(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, always: bool) {
if let ExprKind::Cast(cast_val, _) = expr.kind {
span_lint(
invert: bool,
) {
if let Some((lb, ub)) = lhs_bounds {
- if let Some(norm_rhs_val) = node_as_const_fullint(cx, rhs) {
+ if let Some(norm_rhs_val) = constant_full_int(cx, cx.typeck_results(), rhs) {
if rel == Rel::Eq || rel == Rel::Ne {
if norm_rhs_val < lb || norm_rhs_val > ub {
err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
LintId::of(get_last_with_len::GET_LAST_WITH_LEN),
LintId::of(identity_op::IDENTITY_OP),
LintId::of(if_let_mutex::IF_LET_MUTEX),
- LintId::of(if_then_panic::IF_THEN_PANIC),
LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING),
LintId::of(infinite_iter::INFINITE_ITER),
LintId::of(inherent_to_string::INHERENT_TO_STRING),
LintId::of(non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST),
LintId::of(non_expressive_names::JUST_UNDERSCORES_AND_DIGITS),
LintId::of(non_octal_unix_permissions::NON_OCTAL_UNIX_PERMISSIONS),
+ LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(open_options::NONSENSICAL_OPEN_OPTIONS),
LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
LintId::of(unicode::INVISIBLE_CHARACTERS),
LintId::of(uninit_vec::UNINIT_VEC),
+ LintId::of(unit_hash::UNIT_HASH),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_ARG),
LintId::of(unit_types::UNIT_CMP),
LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
LintId::of(unicode::INVISIBLE_CHARACTERS),
LintId::of(uninit_vec::UNINIT_VEC),
+ LintId::of(unit_hash::UNIT_HASH),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_CMP),
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
identity_op::IDENTITY_OP,
if_let_mutex::IF_LET_MUTEX,
if_not_else::IF_NOT_ELSE,
- if_then_panic::IF_THEN_PANIC,
if_then_some_else_none::IF_THEN_SOME_ELSE_NONE,
implicit_hasher::IMPLICIT_HASHER,
implicit_return::IMPLICIT_RETURN,
loops::WHILE_LET_ON_ITERATOR,
macro_use::MACRO_USE_IMPORTS,
main_recursion::MAIN_RECURSION,
+ manual_assert::MANUAL_ASSERT,
manual_async_fn::MANUAL_ASYNC_FN,
manual_map::MANUAL_MAP,
manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
misc_early::DUPLICATE_UNDERSCORE_ARGUMENT,
misc_early::MIXED_CASE_HEX_LITERALS,
misc_early::REDUNDANT_PATTERN,
+ misc_early::SEPARATED_LITERAL_SUFFIX,
misc_early::UNNEEDED_FIELD_PATTERN,
misc_early::UNNEEDED_WILDCARD_PATTERN,
misc_early::UNSEPARATED_LITERAL_SUFFIX,
strings::STRING_ADD_ASSIGN,
strings::STRING_FROM_UTF8_AS_BYTES,
strings::STRING_LIT_AS_BYTES,
+ strings::STRING_SLICE,
strings::STRING_TO_STRING,
strings::STR_TO_STRING,
strlen_on_c_strings::STRLEN_ON_C_STRINGS,
unicode::NON_ASCII_LITERAL,
unicode::UNICODE_NOT_NFC,
uninit_vec::UNINIT_VEC,
+ unit_hash::UNIT_HASH,
unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
unit_types::LET_UNIT_VALUE,
unit_types::UNIT_ARG,
LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
LintId::of(mutex_atomic::MUTEX_INTEGER),
- LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
LintId::of(option_if_let_else::OPTION_IF_LET_ELSE),
LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE),
LintId::of(loops::EXPLICIT_INTO_ITER_LOOP),
LintId::of(loops::EXPLICIT_ITER_LOOP),
LintId::of(macro_use::MACRO_USE_IMPORTS),
+ LintId::of(manual_assert::MANUAL_ASSERT),
LintId::of(manual_ok_or::MANUAL_OK_OR),
LintId::of(match_on_vec_items::MATCH_ON_VEC_ITEMS),
LintId::of(matches::MATCH_BOOL),
LintId::of(methods::MAP_UNWRAP_OR),
LintId::of(misc::FLOAT_CMP),
LintId::of(misc::USED_UNDERSCORE_BINDING),
- LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
LintId::of(mut_mut::MUT_MUT),
LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL),
LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE),
LintId::of(transmute::TRANSMUTE_PTR_TO_PTR),
LintId::of(types::LINKEDLIST),
LintId::of(types::OPTION_OPTION),
- LintId::of(unicode::NON_ASCII_LITERAL),
LintId::of(unicode::UNICODE_NOT_NFC),
LintId::of(unit_types::LET_UNIT_VALUE),
LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS),
LintId::of(methods::GET_UNWRAP),
LintId::of(methods::UNWRAP_USED),
LintId::of(misc::FLOAT_CMP_CONST),
+ LintId::of(misc_early::SEPARATED_LITERAL_SUFFIX),
LintId::of(misc_early::UNNEEDED_FIELD_PATTERN),
+ LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX),
LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS),
LintId::of(missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES),
LintId::of(missing_inline::MISSING_INLINE_IN_PUBLIC_ITEMS),
LintId::of(shadow::SHADOW_SAME),
LintId::of(shadow::SHADOW_UNRELATED),
LintId::of(strings::STRING_ADD),
+ LintId::of(strings::STRING_SLICE),
LintId::of(strings::STRING_TO_STRING),
LintId::of(strings::STR_TO_STRING),
LintId::of(types::RC_BUFFER),
LintId::of(types::RC_MUTEX),
LintId::of(undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS),
+ LintId::of(unicode::NON_ASCII_LITERAL),
LintId::of(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
LintId::of(functions::DOUBLE_MUST_USE),
LintId::of(functions::MUST_USE_UNIT),
LintId::of(functions::RESULT_UNIT_ERR),
- LintId::of(if_then_panic::IF_THEN_PANIC),
LintId::of(inherent_to_string::INHERENT_TO_STRING),
LintId::of(len_zero::COMPARISON_TO_EMPTY),
LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY),
LintId::of(loops::MUT_RANGE_BOUND),
LintId::of(methods::SUSPICIOUS_MAP),
LintId::of(mut_key::MUTABLE_KEY_TYPE),
+ LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
])
mod identity_op;
mod if_let_mutex;
mod if_not_else;
-mod if_then_panic;
mod if_then_some_else_none;
mod implicit_hasher;
mod implicit_return;
mod loops;
mod macro_use;
mod main_recursion;
+mod manual_assert;
mod manual_async_fn;
mod manual_map;
mod manual_non_exhaustive;
mod undropped_manually_drops;
mod unicode;
mod uninit_vec;
+mod unit_hash;
mod unit_return_expecting_ord;
mod unit_types;
mod unnamed_address;
store.register_late_pass(|| Box::new(collapsible_match::CollapsibleMatch));
store.register_late_pass(|| Box::new(unicode::Unicode));
store.register_late_pass(|| Box::new(uninit_vec::UninitVec));
+ store.register_late_pass(|| Box::new(unit_hash::UnitHash));
store.register_late_pass(|| Box::new(unit_return_expecting_ord::UnitReturnExpectingOrd));
store.register_late_pass(|| Box::new(strings::StringAdd));
store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
store.register_early_pass(|| Box::new(double_parens::DoubleParens));
store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new()));
store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
- store.register_early_pass(|| Box::new(if_not_else::IfNotElse));
store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
store.register_early_pass(|| Box::new(formatting::Formatting));
store.register_late_pass(|| Box::new(option_if_let_else::OptionIfLetElse));
store.register_late_pass(|| Box::new(future_not_send::FutureNotSend));
store.register_late_pass(|| Box::new(if_let_mutex::IfLetMutex));
+ store.register_late_pass(|| Box::new(if_not_else::IfNotElse));
store.register_late_pass(|| Box::new(equatable_if_let::PatternEquality));
store.register_late_pass(|| Box::new(mut_mutex_lock::MutMutexLock));
store.register_late_pass(|| Box::new(match_on_vec_items::MatchOnVecItems));
store.register_late_pass(move || Box::new(self_named_constructors::SelfNamedConstructors));
store.register_late_pass(move || Box::new(feature_name::FeatureName));
store.register_late_pass(move || Box::new(iter_not_returning_iterator::IterNotReturningIterator));
- store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic));
+ store.register_late_pass(move || Box::new(manual_assert::ManualAssert));
let enable_raw_pointer_heuristic_for_send = conf.enable_raw_pointer_heuristic_for_send;
store.register_late_pass(move || Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(enable_raw_pointer_heuristic_for_send)));
store.register_late_pass(move || Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::default()));
store.register_late_pass(|| Box::new(match_str_case_mismatch::MatchStrCaseMismatch));
store.register_late_pass(move || Box::new(format_args::FormatArgs));
store.register_late_pass(|| Box::new(trailing_empty_array::TrailingEmptyArray));
-
+ // add lints here, do not remove this comment, it's used in `new_lint`
}
#[rustfmt::skip]
///
/// Used in `./src/driver.rs`.
pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
+ // NOTE: when renaming a lint, add a corresponding test to tests/ui/rename.rs
ls.register_renamed("clippy::stutter", "clippy::module_name_repetitions");
ls.register_renamed("clippy::new_without_default_derive", "clippy::new_without_default");
ls.register_renamed("clippy::cyclomatic_complexity", "clippy::cognitive_complexity");
fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
match ty.kind {
- TyKind::OpaqueDef(item, _) => {
+ TyKind::OpaqueDef(item, bounds) => {
let map = self.cx.tcx.hir();
let item = map.item(item);
walk_item(self, item);
walk_ty(self, ty);
+ self.lts.extend(bounds.iter().filter_map(|bound| match bound {
+ GenericArg::Lifetime(l) => Some(RefLt::Named(l.name.ident().name)),
+ _ => None,
+ }));
},
TyKind::BareFn(&BareFnTy { decl, .. }) => {
let mut sub_visitor = RefVisitor::new(self.cx);
sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(),
meth_name,
)
- }
+ },
_ => format!(
"{}.into_iter()",
sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::higher::PanicExpn;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{is_expn_of, sugg};
+use rustc_errors::Applicability;
+use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects `if`-then-`panic!` that can be replaced with `assert!`.
+ ///
+ /// ### Why is this bad?
+ /// `assert!` is simpler than `if`-then-`panic!`.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let sad_people: Vec<&str> = vec![];
+ /// if !sad_people.is_empty() {
+ /// panic!("there are sad people: {:?}", sad_people);
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let sad_people: Vec<&str> = vec![];
+ /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
+ /// ```
+ pub MANUAL_ASSERT,
+ pedantic,
+ "`panic!` and only a `panic!` in `if`-then statement"
+}
+
+declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
+
+impl LateLintPass<'_> for ManualAssert {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if_chain! {
+ if let Expr {
+ kind: ExprKind:: If(cond, Expr {
+ kind: ExprKind::Block(
+ Block {
+ stmts: [stmt],
+ ..
+ },
+ _),
+ ..
+ }, None),
+ ..
+ } = &expr;
+ if is_expn_of(stmt.span, "panic").is_some();
+ if !matches!(cond.kind, ExprKind::Let(_, _, _));
+ if let StmtKind::Semi(semi) = stmt.kind;
+ if !cx.tcx.sess.source_map().is_multiline(cond.span);
+
+ then {
+ let call = if_chain! {
+ if let ExprKind::Block(block, _) = semi.kind;
+ if let Some(init) = block.expr;
+ then {
+ init
+ } else {
+ semi
+ }
+ };
+ let span = if let Some(panic_expn) = PanicExpn::parse(call) {
+ match *panic_expn.format_args.value_args {
+ [] => panic_expn.format_args.format_string_span,
+ [.., last] => panic_expn.format_args.format_string_span.to(last.span),
+ }
+ } else if let ExprKind::Call(_, [format_args]) = call.kind {
+ format_args.span
+ } else {
+ return
+ };
+ let mut applicability = Applicability::MachineApplicable;
+ let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
+ let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind {
+ if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e {
+ sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string()
+ } else {
+ format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par())
+ }
+ } else {
+ format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par())
+ };
+
+ span_lint_and_sugg(
+ cx,
+ MANUAL_ASSERT,
+ expr.span,
+ "only a `panic!` in `if`-then statement",
+ "try",
+ format!("assert!({}, {});", cond_sugg, sugg),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
+}
fn verify_case<'a>(case_method: &'a CaseMethod, arms: &'a [Arm<'_>]) -> Option<(Span, SymbolStr)> {
let case_check = match case_method {
- CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(char::is_lowercase) },
- CaseMethod::AsciiLowerCase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'a'..='z')) },
- CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(char::is_uppercase) },
- CaseMethod::AsciiUppercase => |input: &str| -> bool { input.chars().all(|c| matches!(c, 'A'..='Z')) },
+ CaseMethod::LowerCase => |input: &str| -> bool { input.chars().all(|c| c.to_lowercase().next() == Some(c)) },
+ CaseMethod::AsciiLowerCase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_uppercase()) },
+ CaseMethod::UpperCase => |input: &str| -> bool { input.chars().all(|c| c.to_uppercase().next() == Some(c)) },
+ CaseMethod::AsciiUppercase => |input: &str| -> bool { !input.chars().any(|c| c.is_ascii_lowercase()) },
};
for arm in arms {
fn lint(cx: &LateContext<'_>, case_method: &CaseMethod, bad_case_span: Span, bad_case_str: &str) {
let (method_str, suggestion) = match case_method {
- CaseMethod::LowerCase => ("to_lower_case", bad_case_str.to_lowercase()),
+ CaseMethod::LowerCase => ("to_lowercase", bad_case_str.to_lowercase()),
CaseMethod::AsciiLowerCase => ("to_ascii_lowercase", bad_case_str.to_ascii_lowercase()),
CaseMethod::UpperCase => ("to_uppercase", bad_case_str.to_uppercase()),
CaseMethod::AsciiUppercase => ("to_ascii_uppercase", bad_case_str.to_ascii_uppercase()),
-use clippy_utils::consts::{constant, miri_to_const, Constant};
+use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
use clippy_utils::diagnostics::{
multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
};
fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
- let type_ranges = type_ranges(&ranges);
- if !type_ranges.is_empty() {
- if let Some((start, end)) = overlapping(&type_ranges) {
+ if !ranges.is_empty() {
+ if let Some((start, end)) = overlapping(&ranges) {
span_lint_and_note(
cx,
MATCH_OVERLAPPING_ARM,
}
if_chain! {
if matching_wild;
- if let ExprKind::Block(block, _) = arm.body.kind;
- if is_panic_block(block);
+ if is_panic_call(arm.body);
then {
// `Err(_)` or `Err(_e)` arm with `panic!` found
span_lint_and_note(cx,
PatKind::Path(path) => {
#[allow(clippy::match_same_arms)]
let id = match cx.qpath_res(path, pat.hir_id) {
- Res::Def(DefKind::Const | DefKind::ConstParam | DefKind::AnonConst, _) => return,
+ Res::Def(
+ DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
+ _,
+ ) => return,
Res::Def(_, id) => id,
_ => return,
};
}
// If the block contains only a `panic!` macro (as expression or statement)
-fn is_panic_block(block: &Block<'_>) -> bool {
- match (&block.expr, block.stmts.len(), block.stmts.first()) {
- (&Some(exp), 0, _) => is_expn_of(exp.span, "panic").is_some() && is_expn_of(exp.span, "unreachable").is_none(),
- (&None, 1, Some(stmt)) => {
- is_expn_of(stmt.span, "panic").is_some() && is_expn_of(stmt.span, "unreachable").is_none()
- },
- _ => false,
- }
+fn is_panic_call(expr: &Expr<'_>) -> bool {
+ // Unwrap any wrapping blocks
+ let span = if let ExprKind::Block(block, _) = expr.kind {
+ match (&block.expr, block.stmts.len(), block.stmts.first()) {
+ (&Some(exp), 0, _) => exp.span,
+ (&None, 1, Some(stmt)) => stmt.span,
+ _ => return false,
+ }
+ } else {
+ expr.span
+ };
+
+ is_expn_of(span, "panic").is_some() && is_expn_of(span, "unreachable").is_none()
}
fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
}
/// Gets all arms that are unbounded `PatRange`s.
-fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<Constant>> {
+fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<FullInt>> {
arms.iter()
.filter_map(|arm| {
if let Arm { pat, guard: None, .. } = *arm {
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
};
- let rhs = match range_end {
- RangeEnd::Included => Bound::Included(rhs),
- RangeEnd::Excluded => Bound::Excluded(rhs),
+
+ let lhs_val = lhs.int_value(cx, ty)?;
+ let rhs_val = rhs.int_value(cx, ty)?;
+
+ let rhs_bound = match range_end {
+ RangeEnd::Included => Bound::Included(rhs_val),
+ RangeEnd::Excluded => Bound::Excluded(rhs_val),
};
return Some(SpannedRange {
span: pat.span,
- node: (lhs, rhs),
+ node: (lhs_val, rhs_bound),
});
}
if let PatKind::Lit(value) = pat.kind {
- let value = constant(cx, cx.typeck_results(), value)?.0;
+ let value = constant_full_int(cx, cx.typeck_results(), value)?;
return Some(SpannedRange {
span: pat.span,
- node: (value.clone(), Bound::Included(value)),
+ node: (value, Bound::Included(value)),
});
}
}
pub node: (T, Bound<T>),
}
-type TypedRanges = Vec<SpannedRange<u128>>;
-
-/// Gets all `Int` ranges or all `Uint` ranges. Mixed types are an error anyway
-/// and other types than
-/// `Uint` and `Int` probably don't make sense.
-fn type_ranges(ranges: &[SpannedRange<Constant>]) -> TypedRanges {
- ranges
- .iter()
- .filter_map(|range| match range.node {
- (Constant::Int(start), Bound::Included(Constant::Int(end))) => Some(SpannedRange {
- span: range.span,
- node: (start, Bound::Included(end)),
- }),
- (Constant::Int(start), Bound::Excluded(Constant::Int(end))) => Some(SpannedRange {
- span: range.span,
- node: (start, Bound::Excluded(end)),
- }),
- (Constant::Int(start), Bound::Unbounded) => Some(SpannedRange {
- span: range.span,
- node: (start, Bound::Unbounded),
- }),
- _ => None,
- })
- .collect()
-}
-
// Checks if arm has the form `None => None`
fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
if expr.hir_id == self_arg.hir_id && ty != cx.typeck_results().expr_ty_adjusted(expr) =>
{
return;
- }
+ },
ExprKind::MethodCall(_, _, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
| ExprKind::Field(..)
) =>
{
return;
- }
+ },
_ => false,
};
check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None);
}
}
- }
+ },
_ => (),
}
}
-use super::MiscEarlyLints;
use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Expr, ExprKind, UnOp};
use rustc_lint::EarlyContext;
use super::DOUBLE_NEG;
pub(super) fn check(cx: &EarlyContext<'_>, expr: &Expr) {
- match expr.kind {
- ExprKind::Unary(UnOp::Neg, ref inner) => {
- if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
- span_lint(
- cx,
- DOUBLE_NEG,
- expr.span,
- "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
- );
- }
- },
- ExprKind::Lit(ref lit) => MiscEarlyLints::check_lit(cx, lit),
- _ => (),
+ if let ExprKind::Unary(UnOp::Neg, ref inner) = expr.kind {
+ if let ExprKind::Unary(UnOp::Neg, _) = inner.kind {
+ span_lint(
+ cx,
+ DOUBLE_NEG,
+ expr.span,
+ "`--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op",
+ );
+ }
}
}
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::ast::Lit;
+use rustc_errors::Applicability;
+use rustc_lint::EarlyContext;
+
+use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX};
+
+pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
+ let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
+ val
+ } else {
+ return; // It's useless so shouldn't lint.
+ };
+ // Do not lint when literal is unsuffixed.
+ if !suffix.is_empty() {
+ if lit_snip.as_bytes()[maybe_last_sep_idx] == b'_' {
+ span_lint_and_sugg(
+ cx,
+ SEPARATED_LITERAL_SUFFIX,
+ lit.span,
+ &format!("{} type suffix should not be separated by an underscore", sugg_type),
+ "remove the underscore",
+ format!("{}{}", &lit_snip[..maybe_last_sep_idx], suffix),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ span_lint_and_sugg(
+ cx,
+ UNSEPARATED_LITERAL_SUFFIX,
+ lit.span,
+ &format!("{} type suffix should be separated by an underscore", sugg_type),
+ "add an underscore",
+ format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
mod builtin_type_shadow;
mod double_neg;
+mod literal_suffix;
mod mixed_case_hex_literals;
mod redundant_pattern;
mod unneeded_field_pattern;
mod unneeded_wildcard_pattern;
-mod unseparated_literal_suffix;
mod zero_prefixed_literal;
use clippy_utils::diagnostics::span_lint;
use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{Expr, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
+use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
use rustc_ast::visit::FnKind;
use rustc_data_structures::fx::FxHashMap;
use rustc_lint::{EarlyContext, EarlyLintPass};
/// ### What it does
/// Warns if literal suffixes are not separated by an
/// underscore.
+ /// To enforce unseparated literal suffix style,
+ /// see the `separated_literal_suffix` lint.
///
/// ### Why is this bad?
- /// It is much less readable.
+ /// Suffix style should be consistent.
///
/// ### Example
/// ```rust
/// let y = 123832_i32;
/// ```
pub UNSEPARATED_LITERAL_SUFFIX,
- pedantic,
+ restriction,
"literals whose suffix is not separated by an underscore"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Warns if literal suffixes are separated by an underscore.
+ /// To enforce separated literal suffix style,
+ /// see the `unseparated_literal_suffix` lint.
+ ///
+ /// ### Why is this bad?
+ /// Suffix style should be consistent.
+ ///
+ /// ### Example
+ /// ```rust
+ /// // Bad
+ /// let y = 123832_i32;
+ ///
+ /// // Good
+ /// let y = 123832i32;
+ /// ```
+ pub SEPARATED_LITERAL_SUFFIX,
+ restriction,
+ "literals whose suffix is separated by an underscore"
+}
+
declare_clippy_lint! {
/// ### What it does
/// Warns if an integral constant literal starts with `0`.
DOUBLE_NEG,
MIXED_CASE_HEX_LITERALS,
UNSEPARATED_LITERAL_SUFFIX,
+ SEPARATED_LITERAL_SUFFIX,
ZERO_PREFIXED_LITERAL,
BUILTIN_TYPE_SHADOW,
REDUNDANT_PATTERN,
if in_external_macro(cx.sess, expr.span) {
return;
}
+
+ if let ExprKind::Lit(ref lit) = expr.kind {
+ MiscEarlyLints::check_lit(cx, lit);
+ }
double_neg::check(cx, expr);
}
}
LitIntType::Unsigned(ty) => ty.name_str(),
LitIntType::Unsuffixed => "",
};
- unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
+ literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
if lit_snip.starts_with("0x") {
mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
} else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
}
} else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
let suffix = float_ty.name_str();
- unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
+ literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
}
}
}
+++ /dev/null
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_ast::ast::Lit;
-use rustc_errors::Applicability;
-use rustc_lint::EarlyContext;
-
-use super::UNSEPARATED_LITERAL_SUFFIX;
-
-pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
- let maybe_last_sep_idx = if let Some(val) = lit_snip.len().checked_sub(suffix.len() + 1) {
- val
- } else {
- return; // It's useless so shouldn't lint.
- };
- // Do not lint when literal is unsuffixed.
- if !suffix.is_empty() && lit_snip.as_bytes()[maybe_last_sep_idx] != b'_' {
- span_lint_and_sugg(
- cx,
- UNSEPARATED_LITERAL_SUFFIX,
- lit.span,
- &format!("{} type suffix should be separated by an underscore", sugg_type),
- "add an underscore",
- format!("{}_{}", &lit_snip[..=maybe_last_sep_idx], suffix),
- Applicability::MachineApplicable,
- );
- }
-}
}
process_paths_for_mod_files(path, &mut folder_segments, &mut mod_folders);
check_self_named_mod_exists(cx, path, file);
- }
+ },
_ => {},
}
}
if let ExprKind::AddrOf(BorrowKind::Ref, mutability, inner) = e.kind {
if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(inner).kind() {
for adj3 in cx.typeck_results().expr_adjustments(e).windows(3) {
- if let [Adjustment {
- kind: Adjust::Deref(_), ..
- }, Adjustment {
- kind: Adjust::Deref(_), ..
- }, Adjustment {
- kind: Adjust::Borrow(_),
- ..
- }] = *adj3
+ if let [
+ Adjustment {
+ kind: Adjust::Deref(_), ..
+ },
+ Adjustment {
+ kind: Adjust::Deref(_), ..
+ },
+ Adjustment {
+ kind: Adjust::Borrow(_),
+ ..
+ },
+ ] = *adj3
{
let help_msg_ty = if matches!(mutability, Mutability::Not) {
format!("&{}", ty)
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use rustc_ast::ast::{
- Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat, PatKind,
+ self, Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind,
};
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
use rustc_lint::{EarlyContext, EarlyLintPass};
return;
}
- if let ItemKind::Fn(box FnKind(_, ref sig, _, Some(ref blk))) = item.kind {
+ if let ItemKind::Fn(box ast::Fn { ref sig, body: Some(ref blk), .. }) = item.kind {
do_check(self, cx, &item.attrs, &sig.decl, blk);
}
}
return;
}
- if let AssocItemKind::Fn(box FnKind(_, ref sig, _, Some(ref blk))) = item.kind {
+ if let AssocItemKind::Fn(box ast::Fn { ref sig, body: Some(ref blk), .. }) = item.kind {
do_check(self, cx, &item.attrs, &sig.decl, blk);
}
}
/// Use thread-safe types like [`std::sync::Arc`](https://doc.rust-lang.org/std/sync/struct.Arc.html)
/// or specify correct bounds on generic type parameters (`T: Send`).
pub NON_SEND_FIELDS_IN_SEND_TY,
- nursery,
+ suspicious,
"there is field that does not implement `Send` in a `Send` struct"
}
/// expression).
///
/// ### Why is this bad?
- /// Using the dedicated functions of the Option type is clearer and
+ /// Using the dedicated functions of the `Option` type is clearer and
/// more concise than an `if let` expression.
///
/// ### Known problems
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::ptr::get_spans;
use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty};
+use clippy_utils::ty::walk_ptrs_hir_ty;
use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
+use rustc_hir::def::Res;
use rustc_hir::{
- BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, Impl, ImplItem, ImplItemKind, Item,
- ItemKind, Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
+ BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind,
+ Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
impl<'tcx> LateLintPass<'tcx> for Ptr {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
- check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
+ check_fn(cx, sig.decl, Some(body_id));
}
}
return; // ignore trait impls
}
}
- check_fn(cx, sig.decl, item.hir_id(), Some(body_id));
+ check_fn(cx, sig.decl, Some(body_id));
}
}
} else {
None
};
- check_fn(cx, sig.decl, item.hir_id(), body_id);
+ check_fn(cx, sig.decl, body_id);
}
}
}
#[allow(clippy::too_many_lines)]
-fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option<BodyId>) {
- let fn_def_id = cx.tcx.hir().local_def_id(fn_id);
- let sig = cx.tcx.fn_sig(fn_def_id);
- let fn_ty = sig.skip_binder();
+fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>) {
let body = opt_body_id.map(|id| cx.tcx.hir().body(id));
- for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
+ for (idx, arg) in decl.inputs.iter().enumerate() {
// Honor the allow attribute on parameters. See issue 5644.
if let Some(body) = &body {
if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) {
}
}
- if let ty::Ref(_, ty, Mutability::Not) = ty.kind() {
- if is_type_diagnostic_item(cx, ty, sym::Vec) {
+ let (item_name, path) = if_chain! {
+ if let TyKind::Rptr(_, MutTy { ty, mutbl: Mutability::Not }) = arg.kind;
+ if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
+ if let Res::Def(_, did) = path.res;
+ if let Some(item_name) = cx.tcx.get_diagnostic_name(did);
+ then {
+ (item_name, path)
+ } else {
+ continue
+ }
+ };
+
+ match item_name {
+ sym::Vec => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
span_lint_and_then(
cx,
},
);
}
- } else if is_type_diagnostic_item(cx, ty, sym::String) {
+ },
+ sym::String => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
span_lint_and_then(
cx,
},
);
}
- } else if is_type_diagnostic_item(cx, ty, sym::PathBuf) {
+ },
+ sym::PathBuf => {
if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) {
span_lint_and_then(
cx,
},
);
}
- } else if match_type(cx, ty, &paths::COW) {
+ },
+ sym::Cow => {
if_chain! {
- if let TyKind::Rptr(_, MutTy { ty, ..} ) = arg.kind;
- if let TyKind::Path(QPath::Resolved(None, pp)) = ty.kind;
- if let [ref bx] = *pp.segments;
+ if let [ref bx] = *path.segments;
if let Some(params) = bx.args;
if !params.parenthesized;
if let Some(inner) = params.args.iter().find_map(|arg| match arg {
);
}
}
- }
+ },
+ _ => {},
}
}
}
}
- fn expression_returns_unmodified_err(
- cx: &LateContext<'_>,
- expression: &Expr<'_>,
- origin_hir_id: &Expr<'_>,
- ) -> bool {
- match expression.kind {
+ fn expression_returns_unmodified_err(cx: &LateContext<'_>, expr: &Expr<'_>, cond_expr: &Expr<'_>) -> bool {
+ match expr.kind {
ExprKind::Block(block, _) => {
if let Some(return_expression) = Self::return_expression(block) {
- return Self::expression_returns_unmodified_err(cx, return_expression, origin_hir_id);
+ return Self::expression_returns_unmodified_err(cx, return_expression, cond_expr);
}
false
},
- ExprKind::Ret(Some(expr)) | ExprKind::Call(expr, _) => {
- Self::expression_returns_unmodified_err(cx, expr, origin_hir_id)
- },
- ExprKind::Path(_) => path_to_local(expression) == path_to_local(origin_hir_id),
+ ExprKind::Ret(Some(ret_expr)) => Self::expression_returns_unmodified_err(cx, ret_expr, cond_expr),
+ ExprKind::Path(_) => path_to_local(expr) == path_to_local(cond_expr),
_ => false,
}
}
"calling `as_bytes` on a string literal instead of using a byte string literal"
}
-declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN]);
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for slice operations on strings
+ ///
+ /// ### Why is this bad?
+ /// UTF-8 characters span multiple bytes, and it is easy to inadvertently confuse character
+ /// counts and string indices. This may lead to panics, and should warrant some test cases
+ /// containing wide UTF-8 characters. This lint is most useful in code that should avoid
+ /// panics at all costs.
+ ///
+ /// ### Known problems
+ /// Probably lots of false positives. If an index comes from a known valid position (e.g.
+ /// obtained via `char_indices` over the same string), it is totally OK.
+ ///
+ /// # Example
+ /// ```rust,should_panic
+ /// &"Ölkanne"[1..];
+ /// ```
+ pub STRING_SLICE,
+ restriction,
+ "slicing a string"
+}
+
+declare_lint_pass!(StringAdd => [STRING_ADD, STRING_ADD_ASSIGN, STRING_SLICE]);
impl<'tcx> LateLintPass<'tcx> for StringAdd {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if in_external_macro(cx.sess(), e.span) {
return;
}
-
- if let ExprKind::Binary(
- Spanned {
- node: BinOpKind::Add, ..
- },
- left,
- _,
- ) = e.kind
- {
- if is_string(cx, left) {
- if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
- let parent = get_parent_expr(cx, e);
- if let Some(p) = parent {
- if let ExprKind::Assign(target, _, _) = p.kind {
- // avoid duplicate matches
- if SpanlessEq::new(cx).eq_expr(target, left) {
- return;
+ match e.kind {
+ ExprKind::Binary(
+ Spanned {
+ node: BinOpKind::Add, ..
+ },
+ left,
+ _,
+ ) => {
+ if is_string(cx, left) {
+ if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
+ let parent = get_parent_expr(cx, e);
+ if let Some(p) = parent {
+ if let ExprKind::Assign(target, _, _) = p.kind {
+ // avoid duplicate matches
+ if SpanlessEq::new(cx).eq_expr(target, left) {
+ return;
+ }
}
}
}
+ span_lint(
+ cx,
+ STRING_ADD,
+ e.span,
+ "you added something to a string. Consider using `String::push_str()` instead",
+ );
}
- span_lint(
- cx,
- STRING_ADD,
- e.span,
- "you added something to a string. Consider using `String::push_str()` instead",
- );
- }
- } else if let ExprKind::Assign(target, src, _) = e.kind {
- if is_string(cx, target) && is_add(cx, src, target) {
- span_lint(
- cx,
- STRING_ADD_ASSIGN,
- e.span,
- "you assigned the result of adding something to this string. Consider using \
- `String::push_str()` instead",
- );
- }
+ },
+ ExprKind::Assign(target, src, _) => {
+ if is_string(cx, target) && is_add(cx, src, target) {
+ span_lint(
+ cx,
+ STRING_ADD_ASSIGN,
+ e.span,
+ "you assigned the result of adding something to this string. Consider using \
+ `String::push_str()` instead",
+ );
+ }
+ },
+ ExprKind::Index(target, _idx) => {
+ let e_ty = cx.typeck_results().expr_ty(target).peel_refs();
+ if matches!(e_ty.kind(), ty::Str) || is_type_diagnostic_item(cx, e_ty, sym::String) {
+ span_lint(
+ cx,
+ STRING_SLICE,
+ e.span,
+ "indexing into a string may panic if the index is within a UTF-8 character",
+ );
+ }
+ },
+ _ => {},
}
}
}
let file_name = source_map.span_to_filename(between_span);
let source_file = source_map.get_source_file(&file_name)?;
- let lex_start = (between_span.lo().0 + 1) as usize;
- let src_str = source_file.src.as_ref()?[lex_start..between_span.hi().0 as usize].to_string();
+ let lex_start = (between_span.lo().0 - source_file.start_pos.0 + 1) as usize;
+ let lex_end = (between_span.hi().0 - source_file.start_pos.0) as usize;
+ let src_str = source_file.src.as_ref()?[lex_start..lex_end].to_string();
let mut pos = 0;
let mut comment = false;
/// let x = String::from("\u{20ac}");
/// ```
pub NON_ASCII_LITERAL,
- pedantic,
+ restriction,
"using any literal non-ASCII chars in a string literal instead of using the `\\u` escape"
}
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects `().hash(_)`.
+ ///
+ /// ### Why is this bad?
+ /// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::hash::Hash;
+ /// # use std::collections::hash_map::DefaultHasher;
+ /// # enum Foo { Empty, WithValue(u8) }
+ /// # use Foo::*;
+ /// # let mut state = DefaultHasher::new();
+ /// # let my_enum = Foo::Empty;
+ /// match my_enum {
+ /// Empty => ().hash(&mut state),
+ /// WithValue(x) => x.hash(&mut state),
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::hash::Hash;
+ /// # use std::collections::hash_map::DefaultHasher;
+ /// # enum Foo { Empty, WithValue(u8) }
+ /// # use Foo::*;
+ /// # let mut state = DefaultHasher::new();
+ /// # let my_enum = Foo::Empty;
+ /// match my_enum {
+ /// Empty => 0_u8.hash(&mut state),
+ /// WithValue(x) => x.hash(&mut state),
+ /// }
+ /// ```
+ pub UNIT_HASH,
+ correctness,
+ "hashing a unit value, which does nothing"
+}
+declare_lint_pass!(UnitHash => [UNIT_HASH]);
+
+impl LateLintPass<'tcx> for UnitHash {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if_chain! {
+ if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
+ if name_ident.ident.name == sym::hash;
+ if let [recv, state_param] = args;
+ if cx.typeck_results().expr_ty(recv).is_unit();
+ then {
+ span_lint_and_then(
+ cx,
+ UNIT_HASH,
+ expr.span,
+ "this call to `hash` on the unit type will do nothing",
+ |diag| {
+ diag.span_suggestion(
+ expr.span,
+ "remove the call to `hash` or consider using",
+ format!(
+ "0_u8.hash({})",
+ snippet(cx, state_param.span, ".."),
+ ),
+ Applicability::MaybeIncorrect,
+ );
+ diag.note("the implementation of `Hash` for `()` is a no-op");
+ }
+ );
+ }
+ }
+ }
+}
declare_clippy_lint! {
/// ### What it does
- /// Checks for functions of type Result that contain `expect()` or `unwrap()`
+ /// Checks for functions of type `Result` that contain `expect()` or `unwrap()`
///
/// ### Why is this bad?
/// These functions promote recoverable errors to non-recoverable errors which may be undesirable in code bases which wish to avoid panics.
///
/// The list of imports to always rename, a fully qualified path followed by the rename.
(enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
- /// Lint: RESTRICTED_SCRIPTS.
+ /// Lint: DISALLOWED_SCRIPT_IDENTS.
///
/// The list of unicode scripts allowed to be used in the scope.
- (allowed_scripts: Vec<String> = vec!["Latin".to_string()]),
+ (allowed_scripts: Vec<String> = ["Latin"].iter().map(ToString::to_string).collect()),
/// Lint: NON_SEND_FIELDS_IN_SEND_TY.
///
/// Whether to apply the raw pointer heuristic to determine if a type is `Send`.
let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
let mut docs = String::from(&*lines.next()?.as_str());
let mut in_code_block = false;
+ let mut is_code_block_rust = false;
for line in lines {
- docs.push('\n');
let line = line.as_str();
let line = &*line;
+
+ // Rustdoc hides code lines starting with `# ` and this removes them from Clippy's lint list :)
+ if is_code_block_rust && line.trim_start().starts_with("# ") {
+ continue;
+ }
+
+ // The line should be represented in the lint list, even if it's just an empty line
+ docs.push('\n');
if let Some(info) = line.trim_start().strip_prefix("```") {
in_code_block = !in_code_block;
+ is_code_block_rust = false;
if in_code_block {
let lang = info
.trim()
.unwrap_or("rust");
docs.push_str("```");
docs.push_str(lang);
+
+ is_code_block_rust = lang == "rust";
continue;
}
}
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
-use rustc_ast::ast::{Expr, ExprKind, ImplKind, Item, ItemKind, MacCall, Path, StrLit, StrStyle};
+use rustc_ast::ast::{Expr, ExprKind, Impl, Item, ItemKind, MacCall, Path, StrLit, StrStyle};
use rustc_ast::token::{self, LitKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_errors::Applicability;
impl EarlyLintPass for Write {
fn check_item(&mut self, _: &EarlyContext<'_>, item: &Item) {
- if let ItemKind::Impl(box ImplKind {
+ if let ItemKind::Impl(box Impl {
of_trait: Some(trait_ref),
..
}) = &item.kind
(Use(l), Use(r)) => eq_use_tree(l, r),
(Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
(Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
- (Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
+ (Fn(box ast::Fn { defaultness: ld, sig: lf, generics: lg, body: lb }),
+ Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, body: rb })) => {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
(Mod(lu, lmk), Mod(ru, rmk)) => {
(ForeignMod(l), ForeignMod(r)) => {
both(&l.abi, &r.abi, eq_str_lit) && over(&l.items, &r.items, |l, r| eq_item(l, r, eq_foreign_item_kind))
},
- (TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
+ (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt }),
+ TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt })) => {
eq_defaultness(*ld, *rd)
&& eq_generics(lg, rg)
&& over(lb, rb, eq_generic_bound)
(Struct(lv, lg), Struct(rv, rg)) | (Union(lv, lg), Union(rv, rg)) => {
eq_variant_data(lv, rv) && eq_generics(lg, rg)
},
- (Trait(box TraitKind(la, lu, lg, lb, li)), Trait(box TraitKind(ra, ru, rg, rb, ri))) => {
+ (Trait(box ast::Trait { is_auto: la, unsafety: lu, generics: lg, bounds: lb, items: li }),
+ Trait(box ast::Trait { is_auto: ra, unsafety: ru, generics: rg, bounds: rb, items: ri })) => {
la == ra
&& matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
&& eq_generics(lg, rg)
},
(TraitAlias(lg, lb), TraitAlias(rg, rb)) => eq_generics(lg, rg) && over(lb, rb, eq_generic_bound),
(
- Impl(box ImplKind {
+ Impl(box ast::Impl {
unsafety: lu,
polarity: lp,
defaultness: ld,
self_ty: lst,
items: li,
}),
- Impl(box ImplKind {
+ Impl(box ast::Impl {
unsafety: ru,
polarity: rp,
defaultness: rd,
use ForeignItemKind::*;
match (l, r) {
(Static(lt, lm, le), Static(rt, rm, re)) => lm == rm && eq_ty(lt, rt) && eq_expr_opt(le, re),
- (Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
+ (Fn(box ast::Fn { defaultness: ld, sig: lf, generics: lg, body: lb }),
+ Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, body: rb })) => {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
- (TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
+ (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt }),
+ TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt })) => {
eq_defaultness(*ld, *rd)
&& eq_generics(lg, rg)
&& over(lb, rb, eq_generic_bound)
use AssocItemKind::*;
match (l, r) {
(Const(ld, lt, le), Const(rd, rt, re)) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
- (Fn(box FnKind(ld, lf, lg, lb)), Fn(box FnKind(rd, rf, rg, rb))) => {
+ (Fn(box ast::Fn { defaultness: ld, sig: lf, generics: lg, body: lb }),
+ Fn(box ast::Fn { defaultness: rd, sig: rf, generics: rg, body: rb })) => {
eq_defaultness(*ld, *rd) && eq_fn_sig(lf, rf) && eq_generics(lg, rg) && both(lb, rb, |l, r| eq_block(l, r))
},
- (TyAlias(box TyAliasKind(ld, lg, lb, lt)), TyAlias(box TyAliasKind(rd, rg, rb, rt))) => {
+ (TyAlias(box ast::TyAlias { defaultness: ld, generics: lg, bounds: lb, ty: lt }),
+ TyAlias(box ast::TyAlias { defaultness: rd, generics: rg, bounds: rb, ty: rt })) => {
eq_defaultness(*ld, *rd)
&& eq_generics(lg, rg)
&& over(lb, rb, eq_generic_bound)
+++ /dev/null
-/// Returns the index of the character after the first camel-case component of `s`.
-#[must_use]
-pub fn until(s: &str) -> usize {
- let mut iter = s.char_indices();
- if let Some((_, first)) = iter.next() {
- if !first.is_uppercase() {
- return 0;
- }
- } else {
- return 0;
- }
- let mut up = true;
- let mut last_i = 0;
- for (i, c) in iter {
- if up {
- if c.is_lowercase() {
- up = false;
- } else {
- return last_i;
- }
- } else if c.is_uppercase() {
- up = true;
- last_i = i;
- } else if !c.is_lowercase() {
- return i;
- }
- }
- if up { last_i } else { s.len() }
-}
-
-/// Returns index of the last camel-case component of `s`.
-#[must_use]
-pub fn from(s: &str) -> usize {
- let mut iter = s.char_indices().rev();
- if let Some((_, first)) = iter.next() {
- if !first.is_lowercase() {
- return s.len();
- }
- } else {
- return s.len();
- }
- let mut down = true;
- let mut last_i = s.len();
- for (i, c) in iter {
- if down {
- if c.is_uppercase() {
- down = false;
- last_i = i;
- } else if !c.is_lowercase() {
- return last_i;
- }
- } else if c.is_lowercase() {
- down = true;
- } else if c.is_uppercase() {
- last_i = i;
- } else {
- return last_i;
- }
- }
- last_i
-}
-
-#[cfg(test)]
-mod test {
- use super::{from, until};
-
- #[test]
- fn from_full() {
- assert_eq!(from("AbcDef"), 0);
- assert_eq!(from("Abc"), 0);
- assert_eq!(from("ABcd"), 0);
- assert_eq!(from("ABcdEf"), 0);
- assert_eq!(from("AabABcd"), 0);
- }
-
- #[test]
- fn from_partial() {
- assert_eq!(from("abcDef"), 3);
- assert_eq!(from("aDbc"), 1);
- assert_eq!(from("aabABcd"), 3);
- }
-
- #[test]
- fn from_not() {
- assert_eq!(from("AbcDef_"), 7);
- assert_eq!(from("AbcDD"), 5);
- }
-
- #[test]
- fn from_caps() {
- assert_eq!(from("ABCD"), 4);
- }
-
- #[test]
- fn until_full() {
- assert_eq!(until("AbcDef"), 6);
- assert_eq!(until("Abc"), 3);
- }
-
- #[test]
- fn until_not() {
- assert_eq!(until("abcDef"), 0);
- assert_eq!(until("aDbc"), 0);
- }
-
- #[test]
- fn until_partial() {
- assert_eq!(until("AbcDef_"), 6);
- assert_eq!(until("CallTypeC"), 8);
- assert_eq!(until("AbcDD"), 3);
- }
-
- #[test]
- fn until_caps() {
- assert_eq!(until("ABCD"), 0);
- }
-}
_ => None,
}
}
+
+ /// Returns the integer value or `None` if `self` or `val_type` is not integer type.
+ pub fn int_value(&self, cx: &LateContext<'_>, val_type: Ty<'_>) -> Option<FullInt> {
+ if let Constant::Int(const_int) = *self {
+ match *val_type.kind() {
+ ty::Int(ity) => Some(FullInt::S(sext(cx.tcx, const_int, ity))),
+ ty::Uint(_) => Some(FullInt::U(const_int)),
+ _ => None,
+ }
+ } else {
+ None
+ }
+ }
}
/// Parses a `LitKind` to a `Constant`.
constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
}
+pub fn constant_full_int(
+ lcx: &LateContext<'tcx>,
+ typeck_results: &ty::TypeckResults<'tcx>,
+ e: &Expr<'_>,
+) -> Option<FullInt> {
+ constant_simple(lcx, typeck_results, e)?.int_value(lcx, typeck_results.expr_ty(e))
+}
+
+#[derive(Copy, Clone, Debug, Eq)]
+pub enum FullInt {
+ S(i128),
+ U(u128),
+}
+
+impl PartialEq for FullInt {
+ #[must_use]
+ fn eq(&self, other: &Self) -> bool {
+ self.cmp(other) == Ordering::Equal
+ }
+}
+
+impl PartialOrd for FullInt {
+ #[must_use]
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for FullInt {
+ #[must_use]
+ fn cmp(&self, other: &Self) -> Ordering {
+ use FullInt::{S, U};
+
+ fn cmp_s_u(s: i128, u: u128) -> Ordering {
+ u128::try_from(s).map_or(Ordering::Less, |x| x.cmp(&u))
+ }
+
+ match (*self, *other) {
+ (S(s), S(o)) => s.cmp(&o),
+ (U(s), U(o)) => s.cmp(&o),
+ (S(s), U(o)) => cmp_s_u(s, o),
+ (U(s), S(o)) => cmp_s_u(o, s).reverse(),
+ }
+ }
+}
+
/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`.
pub fn constant_context<'a, 'tcx>(
lcx: &'a LateContext<'tcx>,
/// 6 | let other_f64_nan = 0.0f64 / 0.0;
/// | ^^^^^^^^^^^^
/// |
-/// = help: Consider using `f64::NAN` if you would like a constant representing NaN
+/// = help: consider using `f64::NAN` if you would like a constant representing NaN
/// ```
pub fn span_lint_and_help<'a, T: LintContext>(
cx: &'a T,
-//! This module contains functions that retrieves specifiec elements.
+//! This module contains functions that retrieve specific elements.
#![deny(clippy::missing_docs_in_private_items)]
if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position);
if let ExprKind::Lit(lit) = &position_field.expr.kind;
if let LitKind::Int(position, _) = lit.node;
+ if let Ok(i) = usize::try_from(position);
+ let arg = &self.args[i];
+ if let ExprKind::Call(_, [arg_name, _]) = arg.kind;
+ if let ExprKind::Field(_, j) = arg_name.kind;
+ if let Ok(j) = j.name.as_str().parse::<usize>();
then {
- let i = usize::try_from(position).unwrap();
- Some(FormatArgsArg { value: self.value_args[i], arg: &self.args[i], fmt: Some(fmt) })
+ Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) })
} else {
None
}
/// Parses an expanded `panic!` invocation
pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
if_chain! {
- if let ExprKind::Block(block, _) = expr.kind;
- if let Some(init) = block.expr;
- if let ExprKind::Call(_, [format_args]) = init.kind;
+ if let ExprKind::Call(_, [format_args]) = expr.kind;
let expn_data = expr.span.ctxt().outer_expn_data();
if let Some(format_args) = FormatArgsExpn::parse(format_args);
then {
}
return Some(VecInitKind::WithExprCapacity(arg.hir_id));
}
- }
+ },
ExprKind::Path(QPath::Resolved(_, path))
if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) =>
{
return Some(VecInitKind::Default);
- }
+ },
_ => (),
}
}
#[allow(clippy::module_name_repetitions)]
pub mod ast_utils;
pub mod attrs;
-pub mod camel_case;
pub mod comparisons;
pub mod consts;
pub mod diagnostics;
pub mod ptr;
pub mod qualify_min_const_fn;
pub mod source;
+pub mod str_utils;
pub mod sugg;
pub mod ty;
pub mod usage;
/// Checks if the top level expression can be moved into a closure as is.
/// Currently checks for:
/// * Break/Continue outside the given loop HIR ids.
-/// * Yield/Return statments.
+/// * Yield/Return statements.
/// * Inline assembly.
/// * Usages of a field of a local where the type of the local can be partially moved.
///
let mut capture_expr_ty = e;
for (parent_id, parent) in cx.tcx.hir().parent_iter(e.hir_id) {
- if let [Adjustment {
- kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
- target,
- }, ref adjust @ ..] = *cx
+ if let [
+ Adjustment {
+ kind: Adjust::Deref(_) | Adjust::Borrow(AutoBorrow::Ref(..)),
+ target,
+ },
+ ref adjust @ ..,
+ ] = *cx
.typeck_results()
.adjustments()
.get(child_id)
for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
match node {
Node::Expr(
- e
- @
- Expr {
+ e @ Expr {
kind: ExprKind::Loop(..) | ExprKind::Closure(..),
..
},
pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
if let ExprKind::Call(
_,
- &[Expr {
- kind: ExprKind::Closure(_, _, body, _, _),
- ..
- }],
+ &[
+ Expr {
+ kind: ExprKind::Closure(_, _, body, _, _),
+ ..
+ },
+ ],
) = body.value.kind
{
if let ExprKind::Block(
vis.found
}
-/// Checks whether item either has `test` attribute appelied, or
+/// Checks whether item either has `test` attribute applied, or
/// is a module with `test` in its name.
///
/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
--- /dev/null
+/// Dealing with sting indices can be hard, this struct ensures that both the
+/// character and byte index are provided for correct indexing.
+#[derive(Debug, Default, PartialEq, Eq)]
+pub struct StrIndex {
+ pub char_index: usize,
+ pub byte_index: usize,
+}
+
+impl StrIndex {
+ pub fn new(char_index: usize, byte_index: usize) -> Self {
+ Self { char_index, byte_index }
+ }
+}
+
+/// Returns the index of the character after the first camel-case component of `s`.
+///
+/// ```
+/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
+/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
+/// assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
+/// assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
+/// ```
+#[must_use]
+pub fn camel_case_until(s: &str) -> StrIndex {
+ let mut iter = s.char_indices().enumerate();
+ if let Some((_char_index, (_, first))) = iter.next() {
+ if !first.is_uppercase() {
+ return StrIndex::new(0, 0);
+ }
+ } else {
+ return StrIndex::new(0, 0);
+ }
+ let mut up = true;
+ let mut last_index = StrIndex::new(0, 0);
+ for (char_index, (byte_index, c)) in iter {
+ if up {
+ if c.is_lowercase() {
+ up = false;
+ } else {
+ return last_index;
+ }
+ } else if c.is_uppercase() {
+ up = true;
+ last_index.byte_index = byte_index;
+ last_index.char_index = char_index;
+ } else if !c.is_lowercase() {
+ return StrIndex::new(char_index, byte_index);
+ }
+ }
+
+ if up {
+ last_index
+ } else {
+ StrIndex::new(s.chars().count(), s.len())
+ }
+}
+
+/// Returns index of the last camel-case component of `s`.
+///
+/// ```
+/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
+/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
+/// assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
+/// assert_eq!(camel_case_start("abcd"), StrIndex::new(4, 4));
+/// assert_eq!(camel_case_start("\u{f6}\u{f6}cd"), StrIndex::new(4, 6));
+/// ```
+#[must_use]
+pub fn camel_case_start(s: &str) -> StrIndex {
+ let char_count = s.chars().count();
+ let range = 0..char_count;
+ let mut iter = range.rev().zip(s.char_indices().rev());
+ if let Some((char_index, (_, first))) = iter.next() {
+ if !first.is_lowercase() {
+ return StrIndex::new(char_index, s.len());
+ }
+ } else {
+ return StrIndex::new(char_count, s.len());
+ }
+ let mut down = true;
+ let mut last_index = StrIndex::new(char_count, s.len());
+ for (char_index, (byte_index, c)) in iter {
+ if down {
+ if c.is_uppercase() {
+ down = false;
+ last_index.byte_index = byte_index;
+ last_index.char_index = char_index;
+ } else if !c.is_lowercase() {
+ return last_index;
+ }
+ } else if c.is_lowercase() {
+ down = true;
+ } else if c.is_uppercase() {
+ last_index.byte_index = byte_index;
+ last_index.char_index = char_index;
+ } else {
+ return last_index;
+ }
+ }
+ last_index
+}
+
+/// Dealing with sting comparison can be complicated, this struct ensures that both the
+/// character and byte count are provided for correct indexing.
+#[derive(Debug, Default, PartialEq, Eq)]
+pub struct StrCount {
+ pub char_count: usize,
+ pub byte_count: usize,
+}
+
+impl StrCount {
+ pub fn new(char_count: usize, byte_count: usize) -> Self {
+ Self { char_count, byte_count }
+ }
+}
+
+/// Returns the number of chars that match from the start
+///
+/// ```
+/// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6));
+/// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0));
+/// assert_eq!(count_match_start("hello_world", "hello_world"), StrCount::new(11, 11));
+/// assert_eq!(count_match_start("T\u{f6}ffT\u{f6}ff", "T\u{f6}ff"), StrCount::new(4, 5));
+/// ```
+#[must_use]
+pub fn count_match_start(str1: &str, str2: &str) -> StrCount {
+ // (char_index, char1)
+ let char_count = str1.chars().count();
+ let iter1 = (0..=char_count).zip(str1.chars());
+ // (byte_index, char2)
+ let iter2 = str2.char_indices();
+
+ iter1
+ .zip(iter2)
+ .take_while(|((_, c1), (_, c2))| c1 == c2)
+ .last()
+ .map_or_else(StrCount::default, |((char_index, _), (byte_index, character))| {
+ StrCount::new(char_index + 1, byte_index + character.len_utf8())
+ })
+}
+
+/// Returns the number of chars and bytes that match from the end
+///
+/// ```
+/// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4));
+/// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0));
+/// assert_eq!(count_match_end("Clippy", "Clippy"), StrCount::new(6, 6));
+/// assert_eq!(count_match_end("MyT\u{f6}ff", "YourT\u{f6}ff"), StrCount::new(4, 5));
+/// ```
+#[must_use]
+pub fn count_match_end(str1: &str, str2: &str) -> StrCount {
+ let char_count = str1.chars().count();
+ if char_count == 0 {
+ return StrCount::default();
+ }
+
+ // (char_index, char1)
+ let iter1 = (0..char_count).rev().zip(str1.chars().rev());
+ // (byte_index, char2)
+ let byte_count = str2.len();
+ let iter2 = str2.char_indices().rev();
+
+ iter1
+ .zip(iter2)
+ .take_while(|((_, c1), (_, c2))| c1 == c2)
+ .last()
+ .map_or_else(StrCount::default, |((char_index, _), (byte_index, _))| {
+ StrCount::new(char_count - char_index, byte_count - byte_index)
+ })
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn camel_case_start_full() {
+ assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
+ assert_eq!(camel_case_start("Abc"), StrIndex::new(0, 0));
+ assert_eq!(camel_case_start("ABcd"), StrIndex::new(0, 0));
+ assert_eq!(camel_case_start("ABcdEf"), StrIndex::new(0, 0));
+ assert_eq!(camel_case_start("AabABcd"), StrIndex::new(0, 0));
+ }
+
+ #[test]
+ fn camel_case_start_partial() {
+ assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
+ assert_eq!(camel_case_start("aDbc"), StrIndex::new(1, 1));
+ assert_eq!(camel_case_start("aabABcd"), StrIndex::new(3, 3));
+ assert_eq!(camel_case_start("\u{f6}\u{f6}AabABcd"), StrIndex::new(2, 4));
+ }
+
+ #[test]
+ fn camel_case_start_not() {
+ assert_eq!(camel_case_start("AbcDef_"), StrIndex::new(7, 7));
+ assert_eq!(camel_case_start("AbcDD"), StrIndex::new(5, 5));
+ assert_eq!(camel_case_start("all_small"), StrIndex::new(9, 9));
+ assert_eq!(camel_case_start("\u{f6}_all_small"), StrIndex::new(11, 12));
+ }
+
+ #[test]
+ fn camel_case_start_caps() {
+ assert_eq!(camel_case_start("ABCD"), StrIndex::new(4, 4));
+ }
+
+ #[test]
+ fn camel_case_until_full() {
+ assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
+ assert_eq!(camel_case_until("Abc"), StrIndex::new(3, 3));
+ assert_eq!(camel_case_until("Abc\u{f6}\u{f6}\u{f6}"), StrIndex::new(6, 9));
+ }
+
+ #[test]
+ fn camel_case_until_not() {
+ assert_eq!(camel_case_until("abcDef"), StrIndex::new(0, 0));
+ assert_eq!(camel_case_until("aDbc"), StrIndex::new(0, 0));
+ }
+
+ #[test]
+ fn camel_case_until_partial() {
+ assert_eq!(camel_case_until("AbcDef_"), StrIndex::new(6, 6));
+ assert_eq!(camel_case_until("CallTypeC"), StrIndex::new(8, 8));
+ assert_eq!(camel_case_until("AbcDD"), StrIndex::new(3, 3));
+ assert_eq!(camel_case_until("Abc\u{f6}\u{f6}DD"), StrIndex::new(5, 7));
+ }
+
+ #[test]
+ fn until_caps() {
+ assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
+ }
+}
- [Edition 2018 tests](#edition-2018-tests)
- [Testing manually](#testing-manually)
- [Lint declaration](#lint-declaration)
+ - [Lint registration](#lint-registration)
- [Lint passes](#lint-passes)
- [Emitting a lint](#emitting-a-lint)
- [Adding the lint logic](#adding-the-lint-logic)
lint you can run `cargo dev new_lint --name=foo_functions --pass=early
--category=pedantic` (category will default to nursery if not provided). This
command will create two files: `tests/ui/foo_functions.rs` and
-`clippy_lints/src/foo_functions.rs`, as well as run `cargo dev update_lints` to
-register the new lint. For cargo lints, two project hierarchies (fail/pass) will
-be created by default under `tests/ui-cargo`.
+`clippy_lints/src/foo_functions.rs`, as well as
+[registering the lint](#lint-registration). For cargo lints, two project
+hierarchies (fail/pass) will be created by default under `tests/ui-cargo`.
Next, we'll open up these files and add our lint!
impl EarlyLintPass for FooFunctions {}
```
-Normally after declaring the lint, we have to run `cargo dev update_lints`,
-which updates some files, so Clippy knows about the new lint. Since we used
-`cargo dev new_lint ...` to generate the lint declaration, this was done
-automatically. While `update_lints` automates most of the things, it doesn't
-automate everything. We will have to register our lint pass manually in the
-`register_plugins` function in `clippy_lints/src/lib.rs`:
+[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
+[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
+[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
+[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
+
+## Lint registration
+
+When using `cargo dev new_lint`, the lint is automatically registered and
+nothing more has to be done.
+
+When declaring a new lint by hand and `cargo dev update_lints` is used, the lint
+pass may have to be registered manually in the `register_plugins` function in
+`clippy_lints/src/lib.rs`:
```rust
-store.register_early_pass(|| box foo_functions::FooFunctions);
+store.register_early_pass(|| Box::new(foo_functions::FooFunctions));
```
As one may expect, there is a corresponding `register_late_pass` method
available as well. Without a call to one of `register_early_pass` or
`register_late_pass`, the lint pass in question will not be run.
-One reason that `cargo dev` does not automate this step is that multiple lints
-can use the same lint pass, so registering the lint pass may already be done
-when adding a new lint. Another reason that this step is not automated is that
-the order that the passes are registered determines the order the passes
-actually run, which in turn affects the order that any emitted lints are output
-in.
-
-[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
-[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
-[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
-[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
+One reason that `cargo dev update_lints` does not automate this step is that
+multiple lints can use the same lint pass, so registering the lint pass may
+already be done when adding a new lint. Another reason that this step is not
+automated is that the order that the passes are registered determines the order
+the passes actually run, which in turn affects the order that any emitted lints
+are output in.
## Lint passes
/// <The configuration field doc comment>
(configuration_ident: Type = DefaultValue),
```
- The doc comment will be automatically added to the lint documentation.
+ The doc comment is automatically added to the documentation of the listed lints. The default
+ value will be formatted using the `Debug` implementation of the type.
2. Adding the configuration value to the lint impl struct:
1. This first requires the definition of a lint impl struct. Lint impl structs are usually
generated with the `declare_lint_pass!` macro. This struct needs to be defined manually
[toolchain]
-channel = "nightly-2021-10-21"
+channel = "nightly-2021-11-04"
components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
}
fn default_config() -> compiletest::Config {
- let mut config = compiletest::Config::default();
+ let mut config = compiletest::Config {
+ edition: Some("2021".into()),
+ ..compiletest::Config::default()
+ };
if let Ok(filters) = env::var("TESTNAME") {
config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(clippy::assertions_on_constants)]
+#![feature(path_file_prefix)]
+use std::cmp::Ordering;
+use std::ffi::OsStr;
use std::fs::{self, DirEntry};
use std::path::Path;
}
}
-/*
-Test for missing files.
-
-Since rs files are alphabetically before stderr/stdout, we can sort by the full name
-and iter in that order. If we've seen the file stem for the first time and it's not
-a rust file, it means the rust file has to be missing.
-*/
+// Test for missing files.
fn explore_directory(dir: &Path) -> Vec<String> {
let mut missing_files: Vec<String> = Vec::new();
let mut current_file = String::new();
let mut files: Vec<DirEntry> = fs::read_dir(dir).unwrap().filter_map(Result::ok).collect();
- files.sort_by_key(std::fs::DirEntry::path);
+ files.sort_by(|x, y| {
+ match x.path().file_prefix().cmp(&y.path().file_prefix()) {
+ Ordering::Equal => (),
+ ord => return ord,
+ }
+ // Sort rs files before the others if they share the same prefix. So when we see
+ // the file prefix for the first time and it's not a rust file, it means the rust
+ // file has to be missing.
+ match (
+ x.path().extension().and_then(OsStr::to_str),
+ y.path().extension().and_then(OsStr::to_str),
+ ) {
+ (Some("rs"), _) => Ordering::Less,
+ (_, Some("rs")) => Ordering::Greater,
+ _ => Ordering::Equal,
+ }
+ });
for entry in &files {
let path = entry.path();
if path.is_dir() {
missing_files.extend(explore_directory(&path));
} else {
- let file_stem = path.file_stem().unwrap().to_str().unwrap().to_string();
+ let file_prefix = path.file_prefix().unwrap().to_str().unwrap().to_string();
if let Some(ext) = path.extension() {
match ext.to_str().unwrap() {
- "rs" => current_file = file_stem.clone(),
+ "rs" => current_file = file_prefix.clone(),
"stderr" | "stdout" => {
- if file_stem != current_file {
+ if file_prefix != current_file {
missing_files.push(path.to_str().unwrap().to_string());
}
},
-// edition:2018
-
#![warn(clippy::too_many_lines)]
// This function should be considered one line.
error: this function has too many lines (2/1)
- --> $DIR/test.rs:20:1
+ --> $DIR/test.rs:18:1
|
LL | / fn too_many_lines() {
LL | | println!("This is bad.");
= note: `-D clippy::too-many-lines` implied by `-D warnings`
error: this function has too many lines (4/1)
- --> $DIR/test.rs:26:1
+ --> $DIR/test.rs:24:1
|
LL | / async fn async_too_many_lines() {
LL | | println!("This is bad.");
| |_^
error: this function has too many lines (4/1)
- --> $DIR/test.rs:32:1
+ --> $DIR/test.rs:30:1
|
LL | / fn closure_too_many_lines() {
LL | | let _ = {
| |_^
error: this function has too many lines (2/1)
- --> $DIR/test.rs:54:1
+ --> $DIR/test.rs:52:1
|
LL | / fn comment_before_code() {
LL | | let _ = "test";
+#![allow(clippy::excessive_precision)]
#[deny(clippy::unreadable_literal)]
fn allow_inconsistent_digit_grouping() {
error: digits grouped inconsistently by underscores
- --> $DIR/test.rs:18:18
+ --> $DIR/test.rs:19:18
|
LL | let _fail1 = 100_200_300.123456789;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider: `100_200_300.123_456_789`
+//FIXME: suggestions are wrongly expanded, this should be fixed along with #7843
#![allow(non_fmt_panics)]
macro_rules! assert_const {
debug_assert!($len < 0);
};
}
-
fn main() {
assert!(true);
assert!(false);
assert!(false, "false message");
let msg = "panic message";
- assert!(false, msg.to_uppercase());
+ assert!(false, "{}", msg.to_uppercase());
const B: bool = true;
assert!(B);
= help: remove it
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: `assert!(false, "false message")` should probably be replaced
+error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
--> $DIR/assertions_on_constants.rs:14:5
|
LL | assert!(false, "false message");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: use `panic!("false message")` or `unreachable!("false message")`
- = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `assert!(false, msg.to_uppercase())` should probably be replaced
- --> $DIR/assertions_on_constants.rs:17:5
- |
-LL | assert!(false, msg.to_uppercase());
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: use `panic!(msg.to_uppercase())` or `unreachable!(msg.to_uppercase())`
+ = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `assert!(true)` will be optimized out by the compiler
= help: use `panic!()` or `unreachable!()`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: `assert!(false, "C message")` should probably be replaced
+error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
--> $DIR/assertions_on_constants.rs:24:5
|
LL | assert!(C, "C message");
| ^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: use `panic!("C message")` or `unreachable!("C message")`
+ = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
= note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
error: `debug_assert!(true)` will be optimized out by the compiler
= help: remove it
= note: this error originates in the macro `$crate::assert` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
// run-rustfix
-// edition:2018
#![feature(async_closure)]
#![warn(clippy::async_yields_async)]
// run-rustfix
-// edition:2018
#![feature(async_closure)]
#![warn(clippy::async_yields_async)]
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:40:9
+ --> $DIR/async_yields_async.rs:39:9
|
LL | let _h = async {
| ____________________-
|
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:45:9
+ --> $DIR/async_yields_async.rs:44:9
|
LL | let _i = async {
| ____________________-
| |_____- outer async construct
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:51:9
+ --> $DIR/async_yields_async.rs:50:9
|
LL | let _j = async || {
| _______________________-
|
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:56:9
+ --> $DIR/async_yields_async.rs:55:9
|
LL | let _k = async || {
| _______________________-
| |_____- outer async construct
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:58:23
+ --> $DIR/async_yields_async.rs:57:23
|
LL | let _l = async || CustomFutureType;
| ^^^^^^^^^^^^^^^^
| help: consider awaiting this value: `CustomFutureType.await`
error: an async construct yields a type which is itself awaitable
- --> $DIR/async_yields_async.rs:64:9
+ --> $DIR/async_yields_async.rs:63:9
|
LL | let _m = async || {
| _______________________-
-// edition:2018
#![warn(clippy::await_holding_lock)]
use std::sync::Mutex;
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
- --> $DIR/await_holding_lock.rs:7:9
+ --> $DIR/await_holding_lock.rs:6:9
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
= note: `-D clippy::await-holding-lock` implied by `-D warnings`
note: these are all the await points this lock is held through
- --> $DIR/await_holding_lock.rs:7:5
+ --> $DIR/await_holding_lock.rs:6:5
|
LL | / let guard = x.lock().unwrap();
LL | | baz().await
| |_^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
- --> $DIR/await_holding_lock.rs:28:9
+ --> $DIR/await_holding_lock.rs:27:9
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
note: these are all the await points this lock is held through
- --> $DIR/await_holding_lock.rs:28:5
+ --> $DIR/await_holding_lock.rs:27:5
|
LL | / let guard = x.lock().unwrap();
LL | |
| |_^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
- --> $DIR/await_holding_lock.rs:41:13
+ --> $DIR/await_holding_lock.rs:40:13
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
note: these are all the await points this lock is held through
- --> $DIR/await_holding_lock.rs:41:9
+ --> $DIR/await_holding_lock.rs:40:9
|
LL | / let guard = x.lock().unwrap();
LL | | baz().await
| |_____^
error: this MutexGuard is held across an 'await' point. Consider using an async-aware Mutex type or ensuring the MutexGuard is dropped before calling await
- --> $DIR/await_holding_lock.rs:53:13
+ --> $DIR/await_holding_lock.rs:52:13
|
LL | let guard = x.lock().unwrap();
| ^^^^^
|
note: these are all the await points this lock is held through
- --> $DIR/await_holding_lock.rs:53:9
+ --> $DIR/await_holding_lock.rs:52:9
|
LL | / let guard = x.lock().unwrap();
LL | | baz().await
-// edition:2018
#![warn(clippy::await_holding_refcell_ref)]
use std::cell::RefCell;
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:7:9
+ --> $DIR/await_holding_refcell_ref.rs:6:9
|
LL | let b = x.borrow();
| ^
|
= note: `-D clippy::await-holding-refcell-ref` implied by `-D warnings`
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:7:5
+ --> $DIR/await_holding_refcell_ref.rs:6:5
|
LL | / let b = x.borrow();
LL | | baz().await
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:12:9
+ --> $DIR/await_holding_refcell_ref.rs:11:9
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:12:5
+ --> $DIR/await_holding_refcell_ref.rs:11:5
|
LL | / let b = x.borrow_mut();
LL | | baz().await
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:33:9
+ --> $DIR/await_holding_refcell_ref.rs:32:9
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:33:5
+ --> $DIR/await_holding_refcell_ref.rs:32:5
|
LL | / let b = x.borrow_mut();
LL | |
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:45:9
+ --> $DIR/await_holding_refcell_ref.rs:44:9
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:45:5
+ --> $DIR/await_holding_refcell_ref.rs:44:5
|
LL | / let b = x.borrow_mut();
LL | |
| |_^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:60:13
+ --> $DIR/await_holding_refcell_ref.rs:59:13
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:60:9
+ --> $DIR/await_holding_refcell_ref.rs:59:9
|
LL | / let b = x.borrow_mut();
LL | | baz().await
| |_____^
error: this RefCell Ref is held across an 'await' point. Consider ensuring the Ref is dropped before calling await
- --> $DIR/await_holding_refcell_ref.rs:72:13
+ --> $DIR/await_holding_refcell_ref.rs:71:13
|
LL | let b = x.borrow_mut();
| ^
|
note: these are all the await points this ref is held through
- --> $DIR/await_holding_refcell_ref.rs:72:9
+ --> $DIR/await_holding_refcell_ref.rs:71:9
|
LL | / let b = x.borrow_mut();
LL | | baz().await
(1i64).checked_rem_euclid(-1i64).unwrap() as u64;
(1i64).checked_rem_euclid(-1i64).unwrap() as u128;
(1isize).checked_rem_euclid(-1isize).unwrap() as usize;
+
+ // no lint for `cast_possible_truncation`
+ // with `signum` method call (see issue #5395)
+ let x: i64 = 5;
+ let _ = x.signum() as i32;
+
+ let s = x.signum();
+ let _ = s as i32;
+
+ // Test for signed min
+ (-99999999999i64).min(1) as i8; // should be linted because signed
+
+ // Test for various operations that remove enough bits for the result to fit
+ (999999u64 & 1) as u8;
+ (999999u64 % 15) as u8;
+ (999999u64 / 0x1_0000_0000_0000) as u16;
+ ({ 999999u64 >> 56 }) as u8;
+ ({
+ let x = 999999u64;
+ x.min(1)
+ }) as u8;
+ 999999u64.clamp(0, 255) as u8;
+ 999999u64.clamp(0, 256) as u8; // should still be linted
}
LL | -1isize as usize;
| ^^^^^^^^^^^^^^^^
-error: aborting due to 22 previous errors
+error: casting `i64` to `i8` may truncate the value
+ --> $DIR/cast.rs:105:5
+ |
+LL | (-99999999999i64).min(1) as i8; // should be linted because signed
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: casting `u64` to `u8` may truncate the value
+ --> $DIR/cast.rs:117:5
+ |
+LL | 999999u64.clamp(0, 256) as u8; // should still be linted
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 24 previous errors
--- /dev/null
+fn zero() {
+ unsafe { 0 };
+}
// in type inference.
#![feature(trivial_bounds)]
#![allow(unused)]
-
trait A {}
impl A for i32 {}
fn unsized_local()
where
- for<'a> Dst<A + 'a>: Sized,
+ for<'a> Dst<dyn A + 'a>: Sized,
{
- let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
+ let x: Dst<dyn A> = *(Box::new(Dst { x: 1 }) as Box<Dst<dyn A>>);
}
fn return_str() -> str
-error: trait objects without an explicit `dyn` are deprecated
- --> $DIR/ice-3969.rs:25:17
+error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/ice-3969.rs:20:10
|
-LL | for<'a> Dst<A + 'a>: Sized,
- | ^^^^^^ help: use `dyn`: `dyn A + 'a`
+LL | str: Sized;
+ | ^^^^^
|
- = note: `-D bare-trait-objects` implied by `-D warnings`
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+ = note: `-D trivial-bounds` implied by `-D warnings`
-error: trait objects without an explicit `dyn` are deprecated
- --> $DIR/ice-3969.rs:27:16
+error: trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/ice-3969.rs:24:30
|
-LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
- | ^ help: use `dyn`: `dyn A`
+LL | for<'a> Dst<dyn A + 'a>: Sized,
+ | ^^^^^
+
+error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters
+ --> $DIR/ice-3969.rs:31:10
|
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+LL | str: Sized,
+ | ^^^^^
-error: trait objects without an explicit `dyn` are deprecated
- --> $DIR/ice-3969.rs:27:57
+error: trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters
+ --> $DIR/ice-3969.rs:38:13
|
-LL | let x: Dst<A> = *(Box::new(Dst { x: 1 }) as Box<Dst<A>>);
- | ^ help: use `dyn`: `dyn A`
+LL | String: ::std::ops::Neg<Output = String>,
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters
+ --> $DIR/ice-3969.rs:45:10
|
- = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
- = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+LL | i32: Iterator,
+ | ^^^^^^^^
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
-// edition:2018
-
// Regression test for https://github.com/rust-lang/rust-clippy/issues/5207
pub async fn bar<'a, T: 'a>(_: T) {}
// originally from glacier fixed/77919.rs
// encountered errors resolving bounds after type-checking
-
trait TypeVal<T> {
const VAL: T;
}
error[E0412]: cannot find type `PhantomData` in this scope
- --> $DIR/ice-6252.rs:9:9
+ --> $DIR/ice-6252.rs:8:9
|
LL | _n: PhantomData,
| ^^^^^^^^^^^ not found in this scope
|
-help: consider importing this struct
+help: consider importing one of these items
+ |
+LL | use core::marker::PhantomData;
+ |
+LL | use serde::__private::PhantomData;
|
LL | use std::marker::PhantomData;
|
error[E0412]: cannot find type `VAL` in this scope
- --> $DIR/ice-6252.rs:11:63
+ --> $DIR/ice-6252.rs:10:63
|
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
| - ^^^ not found in this scope
| help: you might be missing a type parameter: `, VAL`
error[E0046]: not all trait items implemented, missing: `VAL`
- --> $DIR/ice-6252.rs:11:1
+ --> $DIR/ice-6252.rs:10:1
|
LL | const VAL: T;
| ------------- `VAL` from trait
-// edition:2018
#![allow(clippy::never_loop)]
async fn f() {
--- /dev/null
+#![warn(clippy::undocumented_unsafe_blocks)]
+#![allow(clippy::no_effect)]
+
+#[path = "auxiliary/ice-7868-aux.rs"]
+mod zero;
+
+fn main() {}
--- /dev/null
+error: unsafe block missing a safety comment
+ --> $DIR/auxiliary/ice-7868-aux.rs:2:5
+ |
+LL | unsafe { 0 };
+ | ^^^^^^^^^^^^
+ |
+ = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL ~ unsafe { 0 };
+ |
+
+error: aborting due to previous error
+
--- /dev/null
+enum Tila {
+ TyöAlkoi,
+ TyöKeskeytyi,
+ TyöValmis,
+}
+
+fn main() {}
--- /dev/null
+error: all variants have the same prefix: `Työ`
+ --> $DIR/ice-7869.rs:1:1
+ |
+LL | / enum Tila {
+LL | | TyöAlkoi,
+LL | | TyöKeskeytyi,
+LL | | TyöValmis,
+LL | | }
+ | |_^
+ |
+ = note: `-D clippy::enum-variant-names` implied by `-D warnings`
+ = help: remove the prefixes and use full paths to the variants instead of glob imports
+
+error: aborting due to previous error
+
-// edition:2018
-
use serde::Deserialize;
/// Tests that we do not lint for unused underscores in a `MacroAttribute`
-// compile-flags: --edition=2018
#![feature(custom_inner_attributes)]
#![rustfmt::skip]
#![warn(clippy::debug_assert_with_mut_call)]
#![allow(clippy::redundant_closure_call)]
+
struct S;
impl S {
-#[warn(clippy::unstable_as_slice)]
-#[warn(clippy::unstable_as_mut_slice)]
-#[warn(clippy::misaligned_transmute)]
-#[warn(clippy::unused_collect)]
-#[warn(clippy::invalid_ref)]
-#[warn(clippy::into_iter_on_array)]
-#[warn(clippy::unused_label)]
-#[warn(clippy::regex_macro)]
-#[warn(clippy::drop_bounds)]
-#[warn(clippy::temporary_cstring_as_ptr)]
-#[warn(clippy::panic_params)]
-#[warn(clippy::unknown_clippy_lints)]
-#[warn(clippy::find_map)]
-#[warn(clippy::filter_map)]
-#[warn(clippy::pub_enum_variant_names)]
-#[warn(clippy::wrong_pub_self_convention)]
-#[warn(clippy::invalid_atomic_ordering)]
+#![warn(clippy::should_assert_eq)]
+#![warn(clippy::extend_from_slice)]
+#![warn(clippy::range_step_by_zero)]
+#![warn(clippy::unstable_as_slice)]
+#![warn(clippy::unstable_as_mut_slice)]
+#![warn(clippy::misaligned_transmute)]
+#![warn(clippy::assign_ops)]
+#![warn(clippy::if_let_redundant_pattern_matching)]
+#![warn(clippy::unsafe_vector_initialization)]
+#![warn(clippy::unused_collect)]
+#![warn(clippy::replace_consts)]
+#![warn(clippy::regex_macro)]
+#![warn(clippy::find_map)]
+#![warn(clippy::filter_map)]
+#![warn(clippy::pub_enum_variant_names)]
+#![warn(clippy::wrong_pub_self_convention)]
fn main() {}
-error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
- --> $DIR/deprecated.rs:1:8
+error: lint `clippy::should_assert_eq` has been removed: `assert!()` will be more flexible with RFC 2011
+ --> $DIR/deprecated.rs:1:9
|
-LL | #[warn(clippy::unstable_as_slice)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::should_assert_eq)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
-error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
- --> $DIR/deprecated.rs:2:8
+error: lint `clippy::extend_from_slice` has been removed: `.extend_from_slice(_)` is a faster way to extend a Vec by a slice
+ --> $DIR/deprecated.rs:2:9
|
-LL | #[warn(clippy::unstable_as_mut_slice)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::extend_from_slice)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
- --> $DIR/deprecated.rs:3:8
+error: lint `clippy::range_step_by_zero` has been removed: `iterator.step_by(0)` panics nowadays
+ --> $DIR/deprecated.rs:3:9
|
-LL | #[warn(clippy::misaligned_transmute)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::range_step_by_zero)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
- --> $DIR/deprecated.rs:4:8
+error: lint `clippy::unstable_as_slice` has been removed: `Vec::as_slice` has been stabilized in 1.7
+ --> $DIR/deprecated.rs:4:9
|
-LL | #[warn(clippy::unused_collect)]
- | ^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::unstable_as_slice)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
- --> $DIR/deprecated.rs:5:8
+error: lint `clippy::unstable_as_mut_slice` has been removed: `Vec::as_mut_slice` has been stabilized in 1.7
+ --> $DIR/deprecated.rs:5:9
|
-LL | #[warn(clippy::invalid_ref)]
- | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
+LL | #![warn(clippy::unstable_as_mut_slice)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
- --> $DIR/deprecated.rs:6:8
+error: lint `clippy::misaligned_transmute` has been removed: this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr
+ --> $DIR/deprecated.rs:6:9
|
-LL | #[warn(clippy::into_iter_on_array)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
+LL | #![warn(clippy::misaligned_transmute)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::unused_label` has been renamed to `unused_labels`
- --> $DIR/deprecated.rs:7:8
+error: lint `clippy::assign_ops` has been removed: using compound assignment operators (e.g., `+=`) is harmless
+ --> $DIR/deprecated.rs:7:9
|
-LL | #[warn(clippy::unused_label)]
- | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
+LL | #![warn(clippy::assign_ops)]
+ | ^^^^^^^^^^^^^^^^^^
-error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
- --> $DIR/deprecated.rs:8:8
+error: lint `clippy::if_let_redundant_pattern_matching` has been removed: this lint has been changed to redundant_pattern_matching
+ --> $DIR/deprecated.rs:8:9
|
-LL | #[warn(clippy::regex_macro)]
- | ^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::if_let_redundant_pattern_matching)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
- --> $DIR/deprecated.rs:9:8
+error: lint `clippy::unsafe_vector_initialization` has been removed: the replacement suggested by this lint had substantially different behavior
+ --> $DIR/deprecated.rs:9:9
|
-LL | #[warn(clippy::drop_bounds)]
- | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
+LL | #![warn(clippy::unsafe_vector_initialization)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
- --> $DIR/deprecated.rs:10:8
+error: lint `clippy::unused_collect` has been removed: `collect` has been marked as #[must_use] in rustc and that covers all cases of this lint
+ --> $DIR/deprecated.rs:10:9
|
-LL | #[warn(clippy::temporary_cstring_as_ptr)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
+LL | #![warn(clippy::unused_collect)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
- --> $DIR/deprecated.rs:11:8
+error: lint `clippy::replace_consts` has been removed: associated-constants `MIN`/`MAX` of integers are preferred to `{min,max}_value()` and module constants
+ --> $DIR/deprecated.rs:11:9
|
-LL | #[warn(clippy::panic_params)]
- | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
+LL | #![warn(clippy::replace_consts)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
-error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
- --> $DIR/deprecated.rs:12:8
+error: lint `clippy::regex_macro` has been removed: the regex! macro has been removed from the regex crate in 2018
+ --> $DIR/deprecated.rs:12:9
|
-LL | #[warn(clippy::unknown_clippy_lints)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
+LL | #![warn(clippy::regex_macro)]
+ | ^^^^^^^^^^^^^^^^^^^
error: lint `clippy::find_map` has been removed: this lint has been replaced by `manual_find_map`, a more specific lint
- --> $DIR/deprecated.rs:13:8
+ --> $DIR/deprecated.rs:13:9
|
-LL | #[warn(clippy::find_map)]
- | ^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::find_map)]
+ | ^^^^^^^^^^^^^^^^
error: lint `clippy::filter_map` has been removed: this lint has been replaced by `manual_filter_map`, a more specific lint
- --> $DIR/deprecated.rs:14:8
+ --> $DIR/deprecated.rs:14:9
|
-LL | #[warn(clippy::filter_map)]
- | ^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::filter_map)]
+ | ^^^^^^^^^^^^^^^^^^
error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `enum_variant_names` lint for public items
- --> $DIR/deprecated.rs:15:8
+ --> $DIR/deprecated.rs:15:9
|
-LL | #[warn(clippy::pub_enum_variant_names)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #![warn(clippy::pub_enum_variant_names)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid-breaking-exported-api` config option to `false` to enable the `wrong_self_convention` lint for public items
- --> $DIR/deprecated.rs:16:8
- |
-LL | #[warn(clippy::wrong_pub_self_convention)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
- --> $DIR/deprecated.rs:17:8
+ --> $DIR/deprecated.rs:16:9
|
-LL | #[warn(clippy::invalid_atomic_ordering)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
+LL | #![warn(clippy::wrong_pub_self_convention)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 17 previous errors
+error: aborting due to 16 previous errors
};
}
+#[derive(Copy, Clone)]
pub struct S;
impl S {
pub fn f(&self) -> &Self {
m!(self)
}
- pub fn f_mut(&self) -> &Self {
+ #[allow(unused_mut)] // mut will be unused, once the macro is fixed
+ pub fn f_mut(mut self) -> Self {
m_mut!(self)
}
}
};
}
+#[derive(Copy, Clone)]
pub struct S;
impl S {
pub fn f(&self) -> &Self {
m!(self)
}
- pub fn f_mut(&self) -> &Self {
+ #[allow(unused_mut)] // mut will be unused, once the macro is fixed
+ pub fn f_mut(mut self) -> Self {
m_mut!(self)
}
}
#![warn(clippy::diverging_sub_expression)]
#![allow(clippy::match_same_arms, clippy::logic_bug)]
-
#[allow(clippy::empty_loop)]
fn diverge() -> ! {
loop {}
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:20:10
+ --> $DIR/diverging_sub_expression.rs:19:10
|
LL | b || diverge();
| ^^^^^^^^^
= note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:21:10
+ --> $DIR/diverging_sub_expression.rs:20:10
|
LL | b || A.foo();
| ^^^^^^^
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:30:26
+ --> $DIR/diverging_sub_expression.rs:29:26
|
LL | 6 => true || return,
| ^^^^^^
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:31:26
+ --> $DIR/diverging_sub_expression.rs:30:26
|
LL | 7 => true || continue,
| ^^^^^^^^
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:34:26
+ --> $DIR/diverging_sub_expression.rs:33:26
|
LL | 3 => true || diverge(),
| ^^^^^^^^^
error: sub-expression diverges
- --> $DIR/diverging_sub_expression.rs:39:26
+ --> $DIR/diverging_sub_expression.rs:36:30
+ |
+LL | _ => true || panic!("boo"),
+ | ^^^^^^^^^^^^^
+ |
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: sub-expression diverges
+ --> $DIR/diverging_sub_expression.rs:38:26
|
LL | _ => true || break,
| ^^^^^
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
--- /dev/null
+// run-rustfix
+//! This file tests for the `DOC_MARKDOWN` lint.
+
+#![allow(dead_code, incomplete_features)]
+#![warn(clippy::doc_markdown)]
+#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
+#![rustfmt::skip]
+
+/// The `foo_bar` function does _nothing_. See also `foo::bar`. (note the dot there)
+/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not `Foo::some_fun`
+/// which should be reported only once despite being __doubly bad__.
+/// Here be `::a::global:path`, and _`::another::global::path`_. :: is not a path though.
+/// Import an item from `::awesome::global::blob::` (Intended postfix)
+/// These are the options for `::Cat`: (Intended trailing single colon, shouldn't be linted)
+/// That's not code ~`NotInCodeBlock`~.
+/// `be_sure_we_got_to_the_end_of_it`
+fn foo_bar() {
+}
+
+/// That one tests multiline ticks.
+/// ```rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ```
+///
+/// ~~~rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ~~~
+/// `be_sure_we_got_to_the_end_of_it`
+fn multiline_codeblock() {
+}
+
+/// This _is a test for
+/// multiline
+/// emphasis_.
+/// `be_sure_we_got_to_the_end_of_it`
+fn test_emphasis() {
+}
+
+/// This tests units. See also #835.
+/// kiB MiB GiB TiB PiB EiB
+/// kib Mib Gib Tib Pib Eib
+/// kB MB GB TB PB EB
+/// kb Mb Gb Tb Pb Eb
+/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
+/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
+/// 32kB 32MB 32GB 32TB 32PB 32EB
+/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
+/// NaN
+/// `be_sure_we_got_to_the_end_of_it`
+fn test_units() {
+}
+
+/// This tests allowed identifiers.
+/// KiB MiB GiB TiB PiB EiB
+/// DirectX
+/// ECMAScript
+/// GPLv2 GPLv3
+/// GitHub GitLab
+/// IPv4 IPv6
+/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
+/// NaN NaNs
+/// OAuth GraphQL
+/// OCaml
+/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
+/// WebGL
+/// TensorFlow
+/// TrueType
+/// iOS macOS FreeBSD
+/// TeX LaTeX BibTeX BibLaTeX
+/// MinGW
+/// CamelCase (see also #2395)
+/// `be_sure_we_got_to_the_end_of_it`
+fn test_allowed() {
+}
+
+/// This test has [a `link_with_underscores`][chunked-example] inside it. See #823.
+/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
+/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
+/// It can also be [`inline_link2`].
+///
+/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
+/// [inline_link]: https://foobar
+/// [inline_link2]: https://foobar
+/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
+/// `multiline_ticks` functions.
+///
+/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
+/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
+/// `be_sure_we_got_to_the_end_of_it`
+fn main() {
+ foo_bar();
+ multiline_codeblock();
+ test_emphasis();
+ test_units();
+}
+
+/// ## `CamelCaseThing`
+/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
+///
+/// # `CamelCaseThing`
+///
+/// Not a title #897 `CamelCaseThing`
+/// `be_sure_we_got_to_the_end_of_it`
+fn issue897() {
+}
+
+/// I am confused by brackets? (`x_y`)
+/// I am confused by brackets? (foo `x_y`)
+/// I am confused by brackets? (`x_y` foo)
+/// `be_sure_we_got_to_the_end_of_it`
+fn issue900() {
+}
+
+/// Diesel queries also have a similar problem to [Iterator][iterator], where
+/// /// More talking
+/// returning them from a function requires exposing the implementation of that
+/// function. The [`helper_types`][helper_types] module exists to help with this,
+/// but you might want to hide the return type or have it conditionally change.
+/// Boxing can achieve both.
+///
+/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
+/// [helper_types]: ../helper_types/index.html
+/// `be_sure_we_got_to_the_end_of_it`
+fn issue883() {
+}
+
+/// `foo_bar
+/// baz_quz`
+/// [foo
+/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
+fn multiline() {
+}
+
+/** E.g., serialization of an empty list: `FooBar`
+```
+That's in a code block: `PackedNode`
+```
+
+And `BarQuz` too.
+`be_sure_we_got_to_the_end_of_it`
+*/
+fn issue1073() {
+}
+
+/** E.g., serialization of an empty list: `FooBar`
+```
+That's in a code block: PackedNode
+```
+
+And `BarQuz` too.
+`be_sure_we_got_to_the_end_of_it`
+*/
+fn issue1073_alt() {
+}
+
+/// Tests more than three quotes:
+/// ````
+/// DoNotWarn
+/// ```
+/// StillDont
+/// ````
+/// `be_sure_we_got_to_the_end_of_it`
+fn four_quotes() {
+}
+
+#[cfg_attr(feature = "a", doc = " ```")]
+#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
+/// fn main() {
+/// let s = "localhost:10000".to_string();
+/// println!("{}", s);
+/// }
+/// ```
+fn issue_1469() {}
+
+/**
+ * This is a doc comment that should not be a list
+ *This would also be an error under a strict common mark interpretation
+ */
+fn issue_1920() {}
+
+/// An iterator over `mycrate::Collection`'s values.
+/// It should not lint a `'static` lifetime in ticks.
+fn issue_2210() {}
+
+/// This should not cause the lint to trigger:
+/// #REQ-data-family.lint_partof_exists
+fn issue_2343() {}
+
+/// This should not cause an ICE:
+/// __|_ _|__||_|
+fn pulldown_cmark_crash() {}
+
+/// This should not lint
+/// (regression test for #7758)
+/// [plain text][path::to::item]
+fn intra_doc_link() {}
+
+// issue #7033 - generic_const_exprs ICE
+struct S<T, const N: usize>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+ arr: [T; N.checked_next_power_of_two().unwrap()],
+ n: usize,
+}
+
+impl<T: Copy + Default, const N: usize> S<T, N>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+ fn new() -> Self {
+ Self {
+ arr: [T::default(); N.checked_next_power_of_two().unwrap()],
+ n: 0,
+ }
+ }
+}
--- /dev/null
+// run-rustfix
+//! This file tests for the `DOC_MARKDOWN` lint.
+
+#![allow(dead_code, incomplete_features)]
+#![warn(clippy::doc_markdown)]
+#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
+#![rustfmt::skip]
+
+/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
+/// which should be reported only once despite being __doubly bad__.
+/// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
+/// Import an item from ::awesome::global::blob:: (Intended postfix)
+/// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
+/// That's not code ~NotInCodeBlock~.
+/// be_sure_we_got_to_the_end_of_it
+fn foo_bar() {
+}
+
+/// That one tests multiline ticks.
+/// ```rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ```
+///
+/// ~~~rust
+/// foo_bar FOO_BAR
+/// _foo bar_
+/// ~~~
+/// be_sure_we_got_to_the_end_of_it
+fn multiline_codeblock() {
+}
+
+/// This _is a test for
+/// multiline
+/// emphasis_.
+/// be_sure_we_got_to_the_end_of_it
+fn test_emphasis() {
+}
+
+/// This tests units. See also #835.
+/// kiB MiB GiB TiB PiB EiB
+/// kib Mib Gib Tib Pib Eib
+/// kB MB GB TB PB EB
+/// kb Mb Gb Tb Pb Eb
+/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
+/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
+/// 32kB 32MB 32GB 32TB 32PB 32EB
+/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
+/// NaN
+/// be_sure_we_got_to_the_end_of_it
+fn test_units() {
+}
+
+/// This tests allowed identifiers.
+/// KiB MiB GiB TiB PiB EiB
+/// DirectX
+/// ECMAScript
+/// GPLv2 GPLv3
+/// GitHub GitLab
+/// IPv4 IPv6
+/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
+/// NaN NaNs
+/// OAuth GraphQL
+/// OCaml
+/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
+/// WebGL
+/// TensorFlow
+/// TrueType
+/// iOS macOS FreeBSD
+/// TeX LaTeX BibTeX BibLaTeX
+/// MinGW
+/// CamelCase (see also #2395)
+/// be_sure_we_got_to_the_end_of_it
+fn test_allowed() {
+}
+
+/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
+/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
+/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
+/// It can also be [inline_link2].
+///
+/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
+/// [inline_link]: https://foobar
+/// [inline_link2]: https://foobar
+/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
+/// `multiline_ticks` functions.
+///
+/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
+/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
+/// be_sure_we_got_to_the_end_of_it
+fn main() {
+ foo_bar();
+ multiline_codeblock();
+ test_emphasis();
+ test_units();
+}
+
+/// ## CamelCaseThing
+/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
+///
+/// # CamelCaseThing
+///
+/// Not a title #897 CamelCaseThing
+/// be_sure_we_got_to_the_end_of_it
+fn issue897() {
+}
+
+/// I am confused by brackets? (`x_y`)
+/// I am confused by brackets? (foo `x_y`)
+/// I am confused by brackets? (`x_y` foo)
+/// be_sure_we_got_to_the_end_of_it
+fn issue900() {
+}
+
+/// Diesel queries also have a similar problem to [Iterator][iterator], where
+/// /// More talking
+/// returning them from a function requires exposing the implementation of that
+/// function. The [`helper_types`][helper_types] module exists to help with this,
+/// but you might want to hide the return type or have it conditionally change.
+/// Boxing can achieve both.
+///
+/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
+/// [helper_types]: ../helper_types/index.html
+/// be_sure_we_got_to_the_end_of_it
+fn issue883() {
+}
+
+/// `foo_bar
+/// baz_quz`
+/// [foo
+/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
+fn multiline() {
+}
+
+/** E.g., serialization of an empty list: FooBar
+```
+That's in a code block: `PackedNode`
+```
+
+And BarQuz too.
+be_sure_we_got_to_the_end_of_it
+*/
+fn issue1073() {
+}
+
+/** E.g., serialization of an empty list: FooBar
+```
+That's in a code block: PackedNode
+```
+
+And BarQuz too.
+be_sure_we_got_to_the_end_of_it
+*/
+fn issue1073_alt() {
+}
+
+/// Tests more than three quotes:
+/// ````
+/// DoNotWarn
+/// ```
+/// StillDont
+/// ````
+/// be_sure_we_got_to_the_end_of_it
+fn four_quotes() {
+}
+
+#[cfg_attr(feature = "a", doc = " ```")]
+#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
+/// fn main() {
+/// let s = "localhost:10000".to_string();
+/// println!("{}", s);
+/// }
+/// ```
+fn issue_1469() {}
+
+/**
+ * This is a doc comment that should not be a list
+ *This would also be an error under a strict common mark interpretation
+ */
+fn issue_1920() {}
+
+/// An iterator over mycrate::Collection's values.
+/// It should not lint a `'static` lifetime in ticks.
+fn issue_2210() {}
+
+/// This should not cause the lint to trigger:
+/// #REQ-data-family.lint_partof_exists
+fn issue_2343() {}
+
+/// This should not cause an ICE:
+/// __|_ _|__||_|
+fn pulldown_cmark_crash() {}
+
+/// This should not lint
+/// (regression test for #7758)
+/// [plain text][path::to::item]
+fn intra_doc_link() {}
+
+// issue #7033 - generic_const_exprs ICE
+struct S<T, const N: usize>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+ arr: [T; N.checked_next_power_of_two().unwrap()],
+ n: usize,
+}
+
+impl<T: Copy + Default, const N: usize> S<T, N>
+where [(); N.checked_next_power_of_two().unwrap()]: {
+ fn new() -> Self {
+ Self {
+ arr: [T::default(); N.checked_next_power_of_two().unwrap()],
+ n: 0,
+ }
+ }
+}
--- /dev/null
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:9:9
+ |
+LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+ | ^^^^^^^ help: try: ``foo_bar``
+ |
+ = note: `-D clippy::doc-markdown` implied by `-D warnings`
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:9:51
+ |
+LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
+ | ^^^^^^^^ help: try: ``foo::bar``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:10:83
+ |
+LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
+ | ^^^^^^^^^^^^^ help: try: ``Foo::some_fun``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:12:13
+ |
+LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
+ | ^^^^^^^^^^^^^^^^ help: try: ``::a::global:path``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:12:36
+ |
+LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::another::global::path``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:13:25
+ |
+LL | /// Import an item from ::awesome::global::blob:: (Intended postfix)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``::awesome::global::blob::``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:14:31
+ |
+LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
+ | ^^^^^ help: try: ``::Cat``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:15:22
+ |
+LL | /// That's not code ~NotInCodeBlock~.
+ | ^^^^^^^^^^^^^^ help: try: ``NotInCodeBlock``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:16:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:30:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:37:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:51:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:74:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:78:22
+ |
+LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: ``link_with_underscores``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:81:21
+ |
+LL | /// It can also be [inline_link2].
+ | ^^^^^^^^^^^^ help: try: ``inline_link2``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:91:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:99:8
+ |
+LL | /// ## CamelCaseThing
+ | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:102:7
+ |
+LL | /// # CamelCaseThing
+ | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:104:22
+ |
+LL | /// Not a title #897 CamelCaseThing
+ | ^^^^^^^^^^^^^^ help: try: ``CamelCaseThing``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:105:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:112:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:125:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:136:43
+ |
+LL | /** E.g., serialization of an empty list: FooBar
+ | ^^^^^^ help: try: ``FooBar``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:141:5
+ |
+LL | And BarQuz too.
+ | ^^^^^^ help: try: ``BarQuz``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:142:1
+ |
+LL | be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:147:43
+ |
+LL | /** E.g., serialization of an empty list: FooBar
+ | ^^^^^^ help: try: ``FooBar``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:152:5
+ |
+LL | And BarQuz too.
+ | ^^^^^^ help: try: ``BarQuz``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:153:1
+ |
+LL | be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:164:5
+ |
+LL | /// be_sure_we_got_to_the_end_of_it
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: ``be_sure_we_got_to_the_end_of_it``
+
+error: item in documentation is missing backticks
+ --> $DIR/doc-fixable.rs:183:22
+ |
+LL | /// An iterator over mycrate::Collection's values.
+ | ^^^^^^^^^^^^^^^^^^^ help: try: ``mycrate::Collection``
+
+error: aborting due to 30 previous errors
+
+++ /dev/null
-//! This file tests for the `DOC_MARKDOWN` lint.
-
-#![allow(dead_code, incomplete_features)]
-#![warn(clippy::doc_markdown)]
-#![feature(custom_inner_attributes, generic_const_exprs, const_option)]
-#![rustfmt::skip]
-
-/// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
-/// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
-/// which should be reported only once despite being __doubly bad__.
-/// Here be ::a::global:path.
-/// That's not code ~NotInCodeBlock~.
-/// be_sure_we_got_to_the_end_of_it
-fn foo_bar() {
-}
-
-/// That one tests multiline ticks.
-/// ```rust
-/// foo_bar FOO_BAR
-/// _foo bar_
-/// ```
-///
-/// ~~~rust
-/// foo_bar FOO_BAR
-/// _foo bar_
-/// ~~~
-/// be_sure_we_got_to_the_end_of_it
-fn multiline_codeblock() {
-}
-
-/// This _is a test for
-/// multiline
-/// emphasis_.
-/// be_sure_we_got_to_the_end_of_it
-fn test_emphasis() {
-}
-
-/// This tests units. See also #835.
-/// kiB MiB GiB TiB PiB EiB
-/// kib Mib Gib Tib Pib Eib
-/// kB MB GB TB PB EB
-/// kb Mb Gb Tb Pb Eb
-/// 32kiB 32MiB 32GiB 32TiB 32PiB 32EiB
-/// 32kib 32Mib 32Gib 32Tib 32Pib 32Eib
-/// 32kB 32MB 32GB 32TB 32PB 32EB
-/// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb
-/// NaN
-/// be_sure_we_got_to_the_end_of_it
-fn test_units() {
-}
-
-/// This tests allowed identifiers.
-/// KiB MiB GiB TiB PiB EiB
-/// DirectX
-/// ECMAScript
-/// GPLv2 GPLv3
-/// GitHub GitLab
-/// IPv4 IPv6
-/// ClojureScript CoffeeScript JavaScript PureScript TypeScript
-/// NaN NaNs
-/// OAuth GraphQL
-/// OCaml
-/// OpenGL OpenMP OpenSSH OpenSSL OpenStreetMap OpenDNS
-/// WebGL
-/// TensorFlow
-/// TrueType
-/// iOS macOS FreeBSD
-/// TeX LaTeX BibTeX BibLaTeX
-/// MinGW
-/// CamelCase (see also #2395)
-/// be_sure_we_got_to_the_end_of_it
-fn test_allowed() {
-}
-
-/// This test has [a link_with_underscores][chunked-example] inside it. See #823.
-/// See also [the issue tracker](https://github.com/rust-lang/rust-clippy/search?q=clippy::doc_markdown&type=Issues)
-/// on GitHub (which is a camel-cased word, but is OK). And here is another [inline link][inline_link].
-/// It can also be [inline_link2].
-///
-/// [chunked-example]: https://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example
-/// [inline_link]: https://foobar
-/// [inline_link2]: https://foobar
-/// The `main` function is the entry point of the program. Here it only calls the `foo_bar` and
-/// `multiline_ticks` functions.
-///
-/// expression of the type `_ <bit_op> m <cmp_op> c` (where `<bit_op>`
-/// is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,
-/// be_sure_we_got_to_the_end_of_it
-fn main() {
- foo_bar();
- multiline_codeblock();
- test_emphasis();
- test_units();
-}
-
-/// ## CamelCaseThing
-/// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897.
-///
-/// # CamelCaseThing
-///
-/// Not a title #897 CamelCaseThing
-/// be_sure_we_got_to_the_end_of_it
-fn issue897() {
-}
-
-/// I am confused by brackets? (`x_y`)
-/// I am confused by brackets? (foo `x_y`)
-/// I am confused by brackets? (`x_y` foo)
-/// be_sure_we_got_to_the_end_of_it
-fn issue900() {
-}
-
-/// Diesel queries also have a similar problem to [Iterator][iterator], where
-/// /// More talking
-/// returning them from a function requires exposing the implementation of that
-/// function. The [`helper_types`][helper_types] module exists to help with this,
-/// but you might want to hide the return type or have it conditionally change.
-/// Boxing can achieve both.
-///
-/// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html
-/// [helper_types]: ../helper_types/index.html
-/// be_sure_we_got_to_the_end_of_it
-fn issue883() {
-}
-
-/// `foo_bar
-/// baz_quz`
-/// [foo
-/// bar](https://doc.rust-lang.org/stable/std/iter/trait.IteratorFooBar.html)
-fn multiline() {
-}
-
-/** E.g., serialization of an empty list: FooBar
-```
-That's in a code block: `PackedNode`
-```
-
-And BarQuz too.
-be_sure_we_got_to_the_end_of_it
-*/
-fn issue1073() {
-}
-
-/** E.g., serialization of an empty list: FooBar
-```
-That's in a code block: PackedNode
-```
-
-And BarQuz too.
-be_sure_we_got_to_the_end_of_it
-*/
-fn issue1073_alt() {
-}
-
-/// Tests more than three quotes:
-/// ````
-/// DoNotWarn
-/// ```
-/// StillDont
-/// ````
-/// be_sure_we_got_to_the_end_of_it
-fn four_quotes() {
-}
-
-/// See [NIST SP 800-56A, revision 2].
-///
-/// [NIST SP 800-56A, revision 2]:
-/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
-fn issue_902_comment() {}
-
-#[cfg_attr(feature = "a", doc = " ```")]
-#[cfg_attr(not(feature = "a"), doc = " ```ignore")]
-/// fn main() {
-/// let s = "localhost:10000".to_string();
-/// println!("{}", s);
-/// }
-/// ```
-fn issue_1469() {}
-
-/**
- * This is a doc comment that should not be a list
- *This would also be an error under a strict common mark interpretation
- */
-fn issue_1920() {}
-
-/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
-///
-/// Not ok: http://www.unicode.org
-/// Not ok: https://www.unicode.org
-/// Not ok: http://www.unicode.org/
-/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
-fn issue_1832() {}
-
-/// An iterator over mycrate::Collection's values.
-/// It should not lint a `'static` lifetime in ticks.
-fn issue_2210() {}
-
-/// This should not cause the lint to trigger:
-/// #REQ-data-family.lint_partof_exists
-fn issue_2343() {}
-
-/// This should not cause an ICE:
-/// __|_ _|__||_|
-fn pulldown_cmark_crash() {}
-
-/// This should not lint
-/// (regression test for #7758)
-/// [plain text][path::to::item]
-fn intra_doc_link() {}
-
-// issue #7033 - generic_const_exprs ICE
-struct S<T, const N: usize>
-where [(); N.checked_next_power_of_two().unwrap()]: {
- arr: [T; N.checked_next_power_of_two().unwrap()],
- n: usize,
-}
-
-impl<T: Copy + Default, const N: usize> S<T, N>
-where [(); N.checked_next_power_of_two().unwrap()]: {
- fn new() -> Self {
- Self {
- arr: [T::default(); N.checked_next_power_of_two().unwrap()],
- n: 0,
- }
- }
-}
+++ /dev/null
-error: you should put `foo_bar` between ticks in the documentation
- --> $DIR/doc.rs:8:9
- |
-LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
- | ^^^^^^^
- |
- = note: `-D clippy::doc-markdown` implied by `-D warnings`
-
-error: you should put `foo::bar` between ticks in the documentation
- --> $DIR/doc.rs:8:51
- |
-LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
- | ^^^^^^^^
-
-error: you should put `Foo::some_fun` between ticks in the documentation
- --> $DIR/doc.rs:9:83
- |
-LL | /// Markdown is _weird_. I mean _really weird_. This /_ is ok. So is `_`. But not Foo::some_fun
- | ^^^^^^^^^^^^^
-
-error: you should put `a::global:path` between ticks in the documentation
- --> $DIR/doc.rs:11:15
- |
-LL | /// Here be ::a::global:path.
- | ^^^^^^^^^^^^^^
-
-error: you should put `NotInCodeBlock` between ticks in the documentation
- --> $DIR/doc.rs:12:22
- |
-LL | /// That's not code ~NotInCodeBlock~.
- | ^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:13:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:27:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:34:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:48:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:71:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `link_with_underscores` between ticks in the documentation
- --> $DIR/doc.rs:75:22
- |
-LL | /// This test has [a link_with_underscores][chunked-example] inside it. See #823.
- | ^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `inline_link2` between ticks in the documentation
- --> $DIR/doc.rs:78:21
- |
-LL | /// It can also be [inline_link2].
- | ^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:88:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `CamelCaseThing` between ticks in the documentation
- --> $DIR/doc.rs:96:8
- |
-LL | /// ## CamelCaseThing
- | ^^^^^^^^^^^^^^
-
-error: you should put `CamelCaseThing` between ticks in the documentation
- --> $DIR/doc.rs:99:7
- |
-LL | /// # CamelCaseThing
- | ^^^^^^^^^^^^^^
-
-error: you should put `CamelCaseThing` between ticks in the documentation
- --> $DIR/doc.rs:101:22
- |
-LL | /// Not a title #897 CamelCaseThing
- | ^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:102:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:109:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:122:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `FooBar` between ticks in the documentation
- --> $DIR/doc.rs:133:43
- |
-LL | /** E.g., serialization of an empty list: FooBar
- | ^^^^^^
-
-error: you should put `BarQuz` between ticks in the documentation
- --> $DIR/doc.rs:138:5
- |
-LL | And BarQuz too.
- | ^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:139:1
- |
-LL | be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `FooBar` between ticks in the documentation
- --> $DIR/doc.rs:144:43
- |
-LL | /** E.g., serialization of an empty list: FooBar
- | ^^^^^^
-
-error: you should put `BarQuz` between ticks in the documentation
- --> $DIR/doc.rs:149:5
- |
-LL | And BarQuz too.
- | ^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:150:1
- |
-LL | be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `be_sure_we_got_to_the_end_of_it` between ticks in the documentation
- --> $DIR/doc.rs:161:5
- |
-LL | /// be_sure_we_got_to_the_end_of_it
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
- --> $DIR/doc.rs:188:13
- |
-LL | /// Not ok: http://www.unicode.org
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
- --> $DIR/doc.rs:189:13
- |
-LL | /// Not ok: https://www.unicode.org
- | ^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
- --> $DIR/doc.rs:190:13
- |
-LL | /// Not ok: http://www.unicode.org/
- | ^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put bare URLs between `<`/`>` or make a proper Markdown link
- --> $DIR/doc.rs:191:13
- |
-LL | /// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: you should put `mycrate::Collection` between ticks in the documentation
- --> $DIR/doc.rs:194:22
- |
-LL | /// An iterator over mycrate::Collection's values.
- | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 31 previous errors
-
--- /dev/null
+/// Ok: <http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels>
+///
+/// Not ok: http://www.unicode.org
+/// Not ok: https://www.unicode.org
+/// Not ok: http://www.unicode.org/
+/// Not ok: http://www.unicode.org/reports/tr9/#Reordering_Resolved_Levels
+fn issue_1832() {}
+
+fn main() {}
--- /dev/null
+/// See [NIST SP 800-56A, revision 2].
+///
+/// [NIST SP 800-56A, revision 2]:
+/// https://github.com/rust-lang/rust-clippy/issues/902#issuecomment-261919419
+fn issue_902_comment() {}
+
+fn main() {}
|
= help: a backtick may be missing a pair
-error: you should put `should_be` between ticks in the documentation
+error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:15:32
|
LL | /// This paragraph is fine and should_be linted normally.
- | ^^^^^^^^^
+ | ^^^^^^^^^ help: try: ``should_be``
error: backticks are unbalanced
--> $DIR/unbalanced_ticks.rs:17:1
|
= help: a backtick may be missing a pair
-error: you should put `not_fine` between ticks in the documentation
+error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:30:8
|
LL | /// ## not_fine
- | ^^^^^^^^
+ | ^^^^^^^^ help: try: ``not_fine``
error: backticks are unbalanced
--> $DIR/unbalanced_ticks.rs:32:1
|
= help: a backtick may be missing a pair
-error: you should put `backticks_here` between ticks in the documentation
+error: item in documentation is missing backticks
--> $DIR/unbalanced_ticks.rs:35:23
|
LL | /// - This item needs backticks_here
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^ help: try: ``backticks_here``
error: aborting due to 8 previous errors
-// edition:2018
#![warn(clippy::missing_errors_doc)]
#![allow(clippy::result_unit_err)]
#![allow(clippy::unnecessary_wraps)]
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:8:1
+ --> $DIR/doc_errors.rs:7:1
|
LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
= note: `-D clippy::missing-errors-doc` implied by `-D warnings`
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:12:1
+ --> $DIR/doc_errors.rs:11:1
|
LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
| |_^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:17:1
+ --> $DIR/doc_errors.rs:16:1
|
LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> {
LL | | unimplemented!();
| |_^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:22:1
+ --> $DIR/doc_errors.rs:21:1
|
LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> {
LL | | unimplemented!();
| |_^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:52:5
+ --> $DIR/doc_errors.rs:51:5
|
LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
| |_____^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:57:5
+ --> $DIR/doc_errors.rs:56:5
|
LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> {
LL | | unimplemented!();
| |_____^
error: docs for function returning `Result` missing `# Errors` section
- --> $DIR/doc_errors.rs:86:5
+ --> $DIR/doc_errors.rs:85:5
|
LL | fn trait_method_missing_errors_header() -> Result<(), ()>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
pub unsafe fn f() {}
}
}
+
+/// # Implementation safety
+pub unsafe trait DocumentedUnsafeTraitWithImplementationHeader {
+ fn method();
+}
#[warn(clippy::double_neg)]
+#[allow(clippy::no_effect)]
fn main() {
let x = 1;
-x;
error: `--x` could be misinterpreted as pre-decrement by C programmers, is usually a no-op
- --> $DIR/double_neg.rs:6:5
+ --> $DIR/double_neg.rs:7:5
|
LL | --x;
| ^^^
|
= help: remove the prefixes and use full paths to the variants instead of glob imports
-error: all variants have the same prefix: `With`
+error: all variants have the same prefix: `WithOut`
--> $DIR/enum_variants.rs:81:1
|
LL | / enum Seallll {
-// edition:2018
-
#[warn(clippy::eval_order_dependence)]
#[allow(
unused_assignments,
error: unsequenced read of `x`
- --> $DIR/eval_order_dependence.rs:16:9
+ --> $DIR/eval_order_dependence.rs:14:9
|
LL | } + x;
| ^
|
= note: `-D clippy::eval-order-dependence` implied by `-D warnings`
note: whether read occurs before this write depends on evaluation order
- --> $DIR/eval_order_dependence.rs:14:9
+ --> $DIR/eval_order_dependence.rs:12:9
|
LL | x = 1;
| ^^^^^
error: unsequenced read of `x`
- --> $DIR/eval_order_dependence.rs:19:5
+ --> $DIR/eval_order_dependence.rs:17:5
|
LL | x += {
| ^
|
note: whether read occurs before this write depends on evaluation order
- --> $DIR/eval_order_dependence.rs:20:9
+ --> $DIR/eval_order_dependence.rs:18:9
|
LL | x = 20;
| ^^^^^^
error: unsequenced read of `x`
- --> $DIR/eval_order_dependence.rs:32:12
+ --> $DIR/eval_order_dependence.rs:30:12
|
LL | a: x,
| ^
|
note: whether read occurs before this write depends on evaluation order
- --> $DIR/eval_order_dependence.rs:34:13
+ --> $DIR/eval_order_dependence.rs:32:13
|
LL | x = 6;
| ^^^^^
error: unsequenced read of `x`
- --> $DIR/eval_order_dependence.rs:41:9
+ --> $DIR/eval_order_dependence.rs:39:9
|
LL | x += {
| ^
|
note: whether read occurs before this write depends on evaluation order
- --> $DIR/eval_order_dependence.rs:42:13
+ --> $DIR/eval_order_dependence.rs:40:13
|
LL | x = 20;
| ^^^^^^
#![deny(clippy::fallible_impl_from)]
-#![allow(clippy::if_then_panic)]
// docs example
struct Foo(i32);
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:6:1
+ --> $DIR/fallible_impl_from.rs:5:1
|
LL | / impl From<String> for Foo {
LL | | fn from(s: String) -> Self {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
note: potential failure(s)
- --> $DIR/fallible_impl_from.rs:8:13
+ --> $DIR/fallible_impl_from.rs:7:13
|
LL | Foo(s.parse().unwrap())
| ^^^^^^^^^^^^^^^^^^
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:27:1
+ --> $DIR/fallible_impl_from.rs:26:1
|
LL | / impl From<usize> for Invalid {
LL | | fn from(i: usize) -> Invalid {
|
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
note: potential failure(s)
- --> $DIR/fallible_impl_from.rs:30:13
+ --> $DIR/fallible_impl_from.rs:29:13
|
LL | panic!();
| ^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:36:1
+ --> $DIR/fallible_impl_from.rs:35:1
|
LL | / impl From<Option<String>> for Invalid {
LL | | fn from(s: Option<String>) -> Invalid {
|
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
note: potential failure(s)
- --> $DIR/fallible_impl_from.rs:38:17
+ --> $DIR/fallible_impl_from.rs:37:17
|
LL | let s = s.unwrap();
| ^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^
LL | panic!("{:?}", s);
| ^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: consider implementing `TryFrom` instead
- --> $DIR/fallible_impl_from.rs:54:1
+ --> $DIR/fallible_impl_from.rs:53:1
|
LL | / impl<'a> From<&'a mut <Box<u32> as ProjStrTrait>::ProjString> for Invalid {
LL | | fn from(s: &'a mut <Box<u32> as ProjStrTrait>::ProjString) -> Invalid {
|
= help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail
note: potential failure(s)
- --> $DIR/fallible_impl_from.rs:56:12
+ --> $DIR/fallible_impl_from.rs:55:12
|
LL | if s.parse::<u32>().ok().unwrap() != 42 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | panic!("{:?}", s);
| ^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 4 previous errors
#![warn(clippy::fn_params_excessive_bools)]
+#![allow(clippy::too_many_arguments)]
extern "C" {
fn f(_: bool, _: bool, _: bool, _: bool);
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:17:1
+ --> $DIR/fn_params_excessive_bools.rs:18:1
|
LL | fn g(_: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:20:1
+ --> $DIR/fn_params_excessive_bools.rs:21:1
|
LL | fn t(_: S, _: S, _: Box<S>, _: Vec<u32>, _: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:24:5
+ --> $DIR/fn_params_excessive_bools.rs:25:5
|
LL | fn f(_: bool, _: bool, _: bool, _: bool);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:29:5
+ --> $DIR/fn_params_excessive_bools.rs:30:5
|
LL | fn f(&self, _: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:41:5
+ --> $DIR/fn_params_excessive_bools.rs:42:5
|
LL | / fn n(_: bool, _: u32, _: bool, _: Box<u32>, _: bool, _: bool) {
LL | | fn nn(_: bool, _: bool, _: bool, _: bool) {}
= help: consider refactoring bools into two-variant enums
error: more than 3 bools in function parameters
- --> $DIR/fn_params_excessive_bools.rs:42:9
+ --> $DIR/fn_params_excessive_bools.rs:43:9
|
LL | fn nn(_: bool, _: bool, _: bool, _: bool) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
r##"foo {}
" bar"##.to_string();
+ let _ = String::new();
+
"foo".to_string();
format!("{:?}", "foo"); // Don't warn about `Debug`.
format!("{:8}", "foo");
" bar"##
);
+ let _ = format!("");
+
format!("{}", "foo");
format!("{:?}", "foo"); // Don't warn about `Debug`.
format!("{:8}", "foo");
|
error: useless use of `format!`
- --> $DIR/format.rs:21:5
+ --> $DIR/format.rs:21:13
+ |
+LL | let _ = format!("");
+ | ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
+
+error: useless use of `format!`
+ --> $DIR/format.rs:23:5
|
LL | format!("{}", "foo");
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:25:5
+ --> $DIR/format.rs:27:5
|
LL | format!("{:+}", "foo"); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:26:5
+ --> $DIR/format.rs:28:5
|
LL | format!("{:<}", "foo"); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:31:5
+ --> $DIR/format.rs:33:5
|
LL | format!("{}", arg);
| ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:35:5
+ --> $DIR/format.rs:37:5
|
LL | format!("{:+}", arg); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:36:5
+ --> $DIR/format.rs:38:5
|
LL | format!("{:<}", arg); // Warn when the format makes no difference.
| ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:63:5
+ --> $DIR/format.rs:65:5
|
LL | format!("{}", 42.to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:65:5
+ --> $DIR/format.rs:67:5
|
LL | format!("{}", x.display().to_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
error: useless use of `format!`
- --> $DIR/format.rs:69:18
+ --> $DIR/format.rs:71:18
|
LL | let _ = Some(format!("{}", a + "bar"));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
error: useless use of `format!`
- --> $DIR/format.rs:73:22
+ --> $DIR/format.rs:75:22
|
LL | let _s: String = format!("{}", &*v.join("/n"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
#![allow(unused_variables)]
#![allow(clippy::assertions_on_constants)]
#![allow(clippy::eq_op)]
+#![allow(clippy::print_literal)]
#![warn(clippy::to_string_in_format_args)]
use std::io::{stdout, Write};
println!("{}", Z(1));
println!("{}", **x);
println!("{}", ***x_ref);
+ // https://github.com/rust-lang/rust-clippy/issues/7903
+ println!("{foo}{bar}", foo = "foo", bar = "bar");
+ println!("{foo}{bar}", foo = "foo", bar = "bar");
+ println!("{foo}{bar}", bar = "bar", foo = "foo");
+ println!("{foo}{bar}", bar = "bar", foo = "foo");
+ // negative tests
println!("error: something failed at {}", Somewhere.to_string());
+ // The next two tests are negative because caching the string might be faster than calling `<X as
+ // Display>::fmt` twice.
println!("{} and again {0}", x.to_string());
+ println!("{foo}{foo}", foo = "foo".to_string());
my_macro!();
println!("error: something failed at {}", my_other_macro!());
+ // https://github.com/rust-lang/rust-clippy/issues/7903
+ println!("{foo}{foo:?}", foo = "foo".to_string());
}
#![allow(unused_variables)]
#![allow(clippy::assertions_on_constants)]
#![allow(clippy::eq_op)]
+#![allow(clippy::print_literal)]
#![warn(clippy::to_string_in_format_args)]
use std::io::{stdout, Write};
println!("{}", Z(1).to_string());
println!("{}", x.to_string());
println!("{}", x_ref.to_string());
+ // https://github.com/rust-lang/rust-clippy/issues/7903
+ println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar");
+ println!("{foo}{bar}", foo = "foo", bar = "bar".to_string());
+ println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo");
+ println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
+ // negative tests
println!("error: something failed at {}", Somewhere.to_string());
+ // The next two tests are negative because caching the string might be faster than calling `<X as
+ // Display>::fmt` twice.
println!("{} and again {0}", x.to_string());
+ println!("{foo}{foo}", foo = "foo".to_string());
my_macro!();
println!("error: something failed at {}", my_other_macro!());
+ // https://github.com/rust-lang/rust-clippy/issues/7903
+ println!("{foo}{foo:?}", foo = "foo".to_string());
}
error: `to_string` applied to a type that implements `Display` in `format!` args
- --> $DIR/format_args.rs:75:72
+ --> $DIR/format_args.rs:76:72
|
LL | let _ = format!("error: something failed at {}", Location::caller().to_string());
| ^^^^^^^^^^^^ help: remove this
= note: `-D clippy::to-string-in-format-args` implied by `-D warnings`
error: `to_string` applied to a type that implements `Display` in `write!` args
- --> $DIR/format_args.rs:79:27
+ --> $DIR/format_args.rs:80:27
|
LL | Location::caller().to_string()
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `writeln!` args
- --> $DIR/format_args.rs:84:27
+ --> $DIR/format_args.rs:85:27
|
LL | Location::caller().to_string()
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `print!` args
- --> $DIR/format_args.rs:86:63
+ --> $DIR/format_args.rs:87:63
|
LL | print!("error: something failed at {}", Location::caller().to_string());
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `println!` args
- --> $DIR/format_args.rs:87:65
+ --> $DIR/format_args.rs:88:65
|
LL | println!("error: something failed at {}", Location::caller().to_string());
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `eprint!` args
- --> $DIR/format_args.rs:88:64
+ --> $DIR/format_args.rs:89:64
|
LL | eprint!("error: something failed at {}", Location::caller().to_string());
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `eprintln!` args
- --> $DIR/format_args.rs:89:66
+ --> $DIR/format_args.rs:90:66
|
LL | eprintln!("error: something failed at {}", Location::caller().to_string());
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `format_args!` args
- --> $DIR/format_args.rs:90:77
+ --> $DIR/format_args.rs:91:77
|
LL | let _ = format_args!("error: something failed at {}", Location::caller().to_string());
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `assert!` args
- --> $DIR/format_args.rs:91:70
+ --> $DIR/format_args.rs:92:70
|
LL | assert!(true, "error: something failed at {}", Location::caller().to_string());
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `assert_eq!` args
- --> $DIR/format_args.rs:92:73
+ --> $DIR/format_args.rs:93:73
|
LL | assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `assert_ne!` args
- --> $DIR/format_args.rs:93:73
+ --> $DIR/format_args.rs:94:73
|
LL | assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `panic!` args
- --> $DIR/format_args.rs:94:63
+ --> $DIR/format_args.rs:95:63
|
LL | panic!("error: something failed at {}", Location::caller().to_string());
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `println!` args
- --> $DIR/format_args.rs:95:20
+ --> $DIR/format_args.rs:96:20
|
LL | println!("{}", X(1).to_string());
| ^^^^^^^^^^^^^^^^ help: use this: `*X(1)`
error: `to_string` applied to a type that implements `Display` in `println!` args
- --> $DIR/format_args.rs:96:20
+ --> $DIR/format_args.rs:97:20
|
LL | println!("{}", Y(&X(1)).to_string());
| ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))`
error: `to_string` applied to a type that implements `Display` in `println!` args
- --> $DIR/format_args.rs:97:24
+ --> $DIR/format_args.rs:98:24
|
LL | println!("{}", Z(1).to_string());
| ^^^^^^^^^^^^ help: remove this
error: `to_string` applied to a type that implements `Display` in `println!` args
- --> $DIR/format_args.rs:98:20
+ --> $DIR/format_args.rs:99:20
|
LL | println!("{}", x.to_string());
| ^^^^^^^^^^^^^ help: use this: `**x`
error: `to_string` applied to a type that implements `Display` in `println!` args
- --> $DIR/format_args.rs:99:20
+ --> $DIR/format_args.rs:100:20
|
LL | println!("{}", x_ref.to_string());
| ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref`
-error: aborting due to 17 previous errors
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:102:39
+ |
+LL | println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar");
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:103:52
+ |
+LL | println!("{foo}{bar}", foo = "foo", bar = "bar".to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:104:39
+ |
+LL | println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo");
+ | ^^^^^^^^^^^^ help: remove this
+
+error: `to_string` applied to a type that implements `Display` in `println!` args
+ --> $DIR/format_args.rs:105:52
+ |
+LL | println!("{foo}{bar}", bar = "bar", foo = "foo".to_string());
+ | ^^^^^^^^^^^^ help: remove this
+
+error: aborting due to 21 previous errors
assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
panic!("error: {}", format!("something failed at {}", Location::caller()));
+ // negative tests
println!("error: {}", format_args!("something failed at {}", Location::caller()));
println!("error: {:>70}", format!("something failed at {}", Location::caller()));
println!("error: {} {0}", format!("something failed at {}", Location::caller()));
#![allow(unused_assignments)]
#![allow(clippy::if_same_then_else)]
#![allow(clippy::deref_addrof)]
+#![allow(clippy::nonminimal_bool)]
fn foo() -> bool {
true
error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)`
- --> $DIR/formatting.rs:15:6
+ --> $DIR/formatting.rs:16:6
|
LL | a =- 35;
| ^^^^
= note: to remove this lint, use either `-=` or `= -`
error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
- --> $DIR/formatting.rs:16:6
+ --> $DIR/formatting.rs:17:6
|
LL | a =* &191;
| ^^^^
= note: to remove this lint, use either `*=` or `= *`
error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)`
- --> $DIR/formatting.rs:19:6
+ --> $DIR/formatting.rs:20:6
|
LL | b =! false;
| ^^^^
= note: to remove this lint, use either `!=` or `= !`
error: possibly missing a comma here
- --> $DIR/formatting.rs:28:19
+ --> $DIR/formatting.rs:29:19
|
LL | -1, -2, -3 // <= no comma here
| ^
= note: to remove this lint, add a comma or write the expr in a single line
error: possibly missing a comma here
- --> $DIR/formatting.rs:32:19
+ --> $DIR/formatting.rs:33:19
|
LL | -1, -2, -3 // <= no comma here
| ^
= note: to remove this lint, add a comma or write the expr in a single line
error: possibly missing a comma here
- --> $DIR/formatting.rs:69:11
+ --> $DIR/formatting.rs:70:11
|
LL | -1
| ^
-// edition:2018
#![warn(clippy::future_not_send)]
use std::cell::Cell;
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:8:62
+ --> $DIR/future_not_send.rs:7:62
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ^^^^ future returned by `private_future` is not `Send`
|
= note: `-D clippy::future-not-send` implied by `-D warnings`
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:9:5
+ --> $DIR/future_not_send.rs:8:5
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| -- has type `std::rc::Rc<[u8]>` which is not `Send`
| - `rc` is later dropped here
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:9:5
+ --> $DIR/future_not_send.rs:8:5
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ---- has type `&std::cell::Cell<usize>` which is not `Send`
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:12:42
+ --> $DIR/future_not_send.rs:11:42
|
LL | pub async fn public_future(rc: Rc<[u8]>) {
| ^ future returned by `public_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:13:5
+ --> $DIR/future_not_send.rs:12:5
|
LL | pub async fn public_future(rc: Rc<[u8]>) {
| -- has type `std::rc::Rc<[u8]>` which is not `Send`
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:20:63
+ --> $DIR/future_not_send.rs:19:63
|
LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ^^^^ future returned by `private_future2` is not `Send`
|
note: captured value is not `Send`
- --> $DIR/future_not_send.rs:20:26
+ --> $DIR/future_not_send.rs:19:26
|
LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ^^ has type `std::rc::Rc<[u8]>` which is not `Send`
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
- --> $DIR/future_not_send.rs:20:40
+ --> $DIR/future_not_send.rs:19:40
|
LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
| ^^^^ has type `&std::cell::Cell<usize>` which is not `Send`, because `std::cell::Cell<usize>` is not `Sync`
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:24:43
+ --> $DIR/future_not_send.rs:23:43
|
LL | pub async fn public_future2(rc: Rc<[u8]>) {}
| ^ future returned by `public_future2` is not `Send`
|
note: captured value is not `Send`
- --> $DIR/future_not_send.rs:24:29
+ --> $DIR/future_not_send.rs:23:29
|
LL | pub async fn public_future2(rc: Rc<[u8]>) {}
| ^^ has type `std::rc::Rc<[u8]>` which is not `Send`
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:35:39
+ --> $DIR/future_not_send.rs:34:39
|
LL | async fn private_future(&self) -> usize {
| ^^^^^ future returned by `private_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:36:9
+ --> $DIR/future_not_send.rs:35:9
|
LL | async fn private_future(&self) -> usize {
| ----- has type `&Dummy` which is not `Send`
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:40:39
+ --> $DIR/future_not_send.rs:39:39
|
LL | pub async fn public_future(&self) {
| ^ future returned by `public_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:41:9
+ --> $DIR/future_not_send.rs:40:9
|
LL | pub async fn public_future(&self) {
| ----- has type `&Dummy` which is not `Send`
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:50:37
+ --> $DIR/future_not_send.rs:49:37
|
LL | async fn generic_future<T>(t: T) -> T
| ^ future returned by `generic_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
- --> $DIR/future_not_send.rs:55:5
+ --> $DIR/future_not_send.rs:54:5
|
LL | let rt = &t;
| -- has type `&T` which is not `Send`
= note: `T` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:66:34
+ --> $DIR/future_not_send.rs:65:34
|
LL | async fn unclear_future<T>(t: T) {}
| ^ future returned by `unclear_future` is not `Send`
|
note: captured value is not `Send`
- --> $DIR/future_not_send.rs:66:28
+ --> $DIR/future_not_send.rs:65:28
|
LL | async fn unclear_future<T>(t: T) {}
| ^ has type `T` which is not `Send`
#![warn(clippy::all)]
#![warn(clippy::if_not_else)]
+fn foo() -> bool {
+ unimplemented!()
+}
fn bla() -> bool {
unimplemented!()
}
} else {
println!("Bunny");
}
+ if !foo() {
+ println!("Foo");
+ } else if !bla() {
+ println!("Bugs");
+ } else {
+ println!("Bunny");
+ }
}
error: unnecessary boolean `not` operation
- --> $DIR/if_not_else.rs:9:5
+ --> $DIR/if_not_else.rs:12:5
|
LL | / if !bla() {
LL | | println!("Bugs");
= help: remove the `!` and swap the blocks of the `if`/`else`
error: unnecessary `!=` operation
- --> $DIR/if_not_else.rs:14:5
+ --> $DIR/if_not_else.rs:17:5
|
LL | / if 4 != 5 {
LL | | println!("Bugs");
+++ /dev/null
-// run-rustfix
-#![warn(clippy::if_then_panic)]
-
-fn main() {
- let a = vec![1, 2, 3];
- let c = Some(2);
- if !a.is_empty()
- && a.len() == 3
- && c != None
- && !a.is_empty()
- && a.len() == 3
- && !a.is_empty()
- && a.len() == 3
- && !a.is_empty()
- && a.len() == 3
- {
- panic!("qaqaq{:?}", a);
- }
- assert!(a.is_empty(), "qaqaq{:?}", a);
- assert!(a.is_empty(), "qwqwq");
- if a.len() == 3 {
- println!("qwq");
- println!("qwq");
- println!("qwq");
- }
- if let Some(b) = c {
- panic!("orz {}", b);
- }
- if a.len() == 3 {
- panic!("qaqaq");
- } else {
- println!("qwq");
- }
- let b = vec![1, 2, 3];
- assert!(!b.is_empty(), "panic1");
- assert!(!(b.is_empty() && a.is_empty()), "panic2");
- assert!(!(a.is_empty() && !b.is_empty()), "panic3");
- assert!(!(b.is_empty() || a.is_empty()), "panic4");
- assert!(!(a.is_empty() || !b.is_empty()), "panic5");
-}
+++ /dev/null
-// run-rustfix
-#![warn(clippy::if_then_panic)]
-
-fn main() {
- let a = vec![1, 2, 3];
- let c = Some(2);
- if !a.is_empty()
- && a.len() == 3
- && c != None
- && !a.is_empty()
- && a.len() == 3
- && !a.is_empty()
- && a.len() == 3
- && !a.is_empty()
- && a.len() == 3
- {
- panic!("qaqaq{:?}", a);
- }
- if !a.is_empty() {
- panic!("qaqaq{:?}", a);
- }
- if !a.is_empty() {
- panic!("qwqwq");
- }
- if a.len() == 3 {
- println!("qwq");
- println!("qwq");
- println!("qwq");
- }
- if let Some(b) = c {
- panic!("orz {}", b);
- }
- if a.len() == 3 {
- panic!("qaqaq");
- } else {
- println!("qwq");
- }
- let b = vec![1, 2, 3];
- if b.is_empty() {
- panic!("panic1");
- }
- if b.is_empty() && a.is_empty() {
- panic!("panic2");
- }
- if a.is_empty() && !b.is_empty() {
- panic!("panic3");
- }
- if b.is_empty() || a.is_empty() {
- panic!("panic4");
- }
- if a.is_empty() || !b.is_empty() {
- panic!("panic5");
- }
-}
+++ /dev/null
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:19:5
- |
-LL | / if !a.is_empty() {
-LL | | panic!("qaqaq{:?}", a);
-LL | | }
- | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
- |
- = note: `-D clippy::if-then-panic` implied by `-D warnings`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:22:5
- |
-LL | / if !a.is_empty() {
-LL | | panic!("qwqwq");
-LL | | }
- | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:39:5
- |
-LL | / if b.is_empty() {
-LL | | panic!("panic1");
-LL | | }
- | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:42:5
- |
-LL | / if b.is_empty() && a.is_empty() {
-LL | | panic!("panic2");
-LL | | }
- | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:45:5
- |
-LL | / if a.is_empty() && !b.is_empty() {
-LL | | panic!("panic3");
-LL | | }
- | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:48:5
- |
-LL | / if b.is_empty() || a.is_empty() {
-LL | | panic!("panic4");
-LL | | }
- | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
-
-error: only a `panic!` in `if`-then statement
- --> $DIR/if_then_panic.rs:51:5
- |
-LL | / if a.is_empty() || !b.is_empty() {
-LL | | panic!("panic5");
-LL | | }
- | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
-
-error: aborting due to 7 previous errors
-
-// edition:2018
// aux-build:implicit_hasher_macros.rs
#![deny(clippy::implicit_hasher)]
#![allow(unused)]
error: impl for `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:17:35
+ --> $DIR/implicit_hasher.rs:16:35
|
LL | impl<K: Hash + Eq, V> Foo<i8> for HashMap<K, V> {
| ^^^^^^^^^^^^^
|
note: the lint level is defined here
- --> $DIR/implicit_hasher.rs:3:9
+ --> $DIR/implicit_hasher.rs:2:9
|
LL | #![deny(clippy::implicit_hasher)]
| ^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: impl for `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:26:36
+ --> $DIR/implicit_hasher.rs:25:36
|
LL | impl<K: Hash + Eq, V> Foo<i8> for (HashMap<K, V>,) {
| ^^^^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: impl for `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:31:19
+ --> $DIR/implicit_hasher.rs:30:19
|
LL | impl Foo<i16> for HashMap<String, String> {
| ^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: impl for `HashSet` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:48:32
+ --> $DIR/implicit_hasher.rs:47:32
|
LL | impl<T: Hash + Eq> Foo<i8> for HashSet<T> {
| ^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: impl for `HashSet` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:53:19
+ --> $DIR/implicit_hasher.rs:52:19
|
LL | impl Foo<i16> for HashSet<String> {
| ^^^^^^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: parameter of type `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:70:23
+ --> $DIR/implicit_hasher.rs:69:23
|
LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
| ^^^^^^^^^^^^^^^^^
| +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~
error: parameter of type `HashSet` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:70:53
+ --> $DIR/implicit_hasher.rs:69:53
|
LL | pub fn foo(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
| ^^^^^^^^^^^^
| +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~
error: impl for `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:74:43
+ --> $DIR/implicit_hasher.rs:73:43
|
LL | impl<K: Hash + Eq, V> Foo<u8> for HashMap<K, V> {
| ^^^^^^^^^^^^^
| ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: parameter of type `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:82:33
+ --> $DIR/implicit_hasher.rs:81:33
|
LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
| ^^^^^^^^^^^^^^^^^
| +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~~~~~~
error: parameter of type `HashSet` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:82:63
+ --> $DIR/implicit_hasher.rs:81:63
|
LL | pub fn $name(_map: &mut HashMap<i32, i32>, _set: &mut HashSet<i32>) {}
| ^^^^^^^^^^^^
| +++++++++++++++++++++++++++++ ~~~~~~~~~~~~~~~
error: parameter of type `HashMap` should be generalized over different hashers
- --> $DIR/implicit_hasher.rs:101:35
+ --> $DIR/implicit_hasher.rs:100:35
|
LL | pub async fn election_vote(_data: HashMap<i32, i32>) {}
| ^^^^^^^^^^^^^^^^^
-// edition:2018
// run-rustfix
#![warn(clippy::implicit_return)]
-// edition:2018
// run-rustfix
#![warn(clippy::implicit_return)]
error: missing `return` statement
- --> $DIR/implicit_return.rs:13:5
+ --> $DIR/implicit_return.rs:12:5
|
LL | true
| ^^^^ help: add `return` as shown: `return true`
= note: `-D clippy::implicit-return` implied by `-D warnings`
error: missing `return` statement
- --> $DIR/implicit_return.rs:17:15
+ --> $DIR/implicit_return.rs:16:15
|
LL | if true { true } else { false }
| ^^^^ help: add `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:17:29
+ --> $DIR/implicit_return.rs:16:29
|
LL | if true { true } else { false }
| ^^^^^ help: add `return` as shown: `return false`
error: missing `return` statement
- --> $DIR/implicit_return.rs:23:17
+ --> $DIR/implicit_return.rs:22:17
|
LL | true => false,
| ^^^^^ help: add `return` as shown: `return false`
error: missing `return` statement
- --> $DIR/implicit_return.rs:24:20
+ --> $DIR/implicit_return.rs:23:20
|
LL | false => { true },
| ^^^^ help: add `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:37:9
+ --> $DIR/implicit_return.rs:36:9
|
LL | break true;
| ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:44:13
+ --> $DIR/implicit_return.rs:43:13
|
LL | break true;
| ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:52:13
+ --> $DIR/implicit_return.rs:51:13
|
LL | break true;
| ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:70:18
+ --> $DIR/implicit_return.rs:69:18
|
LL | let _ = || { true };
| ^^^^ help: add `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:71:16
+ --> $DIR/implicit_return.rs:70:16
|
LL | let _ = || true;
| ^^^^ help: add `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:79:5
+ --> $DIR/implicit_return.rs:78:5
|
LL | format!("test {}", "test")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add `return` as shown: `return format!("test {}", "test")`
error: missing `return` statement
- --> $DIR/implicit_return.rs:88:5
+ --> $DIR/implicit_return.rs:87:5
|
LL | m!(true, false)
| ^^^^^^^^^^^^^^^ help: add `return` as shown: `return m!(true, false)`
error: missing `return` statement
- --> $DIR/implicit_return.rs:94:13
+ --> $DIR/implicit_return.rs:93:13
|
LL | break true;
| ^^^^^^^^^^ help: change `break` to `return` as shown: `return true`
error: missing `return` statement
- --> $DIR/implicit_return.rs:99:17
+ --> $DIR/implicit_return.rs:98:17
|
LL | break 'outer false;
| ^^^^^^^^^^^^^^^^^^ help: change `break` to `return` as shown: `return false`
error: missing `return` statement
- --> $DIR/implicit_return.rs:114:5
+ --> $DIR/implicit_return.rs:113:5
|
LL | / loop {
LL | | m!(true);
|
error: missing `return` statement
- --> $DIR/implicit_return.rs:128:5
+ --> $DIR/implicit_return.rs:127:5
|
LL | true
| ^^^^ help: add `return` as shown: `return true`
// run-rustfix
-// edition:2018
#![warn(clippy::inconsistent_struct_constructor)]
#![allow(clippy::redundant_field_names)]
#![allow(clippy::unnecessary_operation)]
// run-rustfix
-// edition:2018
#![warn(clippy::inconsistent_struct_constructor)]
#![allow(clippy::redundant_field_names)]
#![allow(clippy::unnecessary_operation)]
error: struct constructor field order is inconsistent with struct definition field order
- --> $DIR/inconsistent_struct_constructor.rs:34:9
+ --> $DIR/inconsistent_struct_constructor.rs:33:9
|
LL | Foo { y, x, z };
| ^^^^^^^^^^^^^^^ help: try: `Foo { x, y, z }`
= note: `-D clippy::inconsistent-struct-constructor` implied by `-D warnings`
error: struct constructor field order is inconsistent with struct definition field order
- --> $DIR/inconsistent_struct_constructor.rs:56:9
+ --> $DIR/inconsistent_struct_constructor.rs:55:9
|
LL | / Foo {
LL | | z,
--- /dev/null
+error: sub-expression diverges
+ --> $DIR/issue-7447.rs:23:15
+ |
+LL | byte_view(panic!());
+ | ^^^^^^^^
+ |
+ = note: `-D clippy::diverging-sub-expression` implied by `-D warnings`
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: sub-expression diverges
+ --> $DIR/issue-7447.rs:24:19
+ |
+LL | group_entries(panic!());
+ | ^^^^^^^^
+ |
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
-// edition:2018
#![allow(dead_code)]
async fn sink1<'a>(_: &'a str) {} // lint
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/issue_4266.rs:4:1
+ --> $DIR/issue_4266.rs:3:1
|
LL | async fn sink1<'a>(_: &'a str) {} // lint
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::needless-lifetimes` implied by `-D warnings`
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/issue_4266.rs:8:1
+ --> $DIR/issue_4266.rs:7:1
|
LL | async fn one_to_one<'a>(s: &'a str) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
}
+#[allow(unused_must_use)]
fn main() {
let mut vec = vec![0, 1, 2, 3];
let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
linked_list.push_back(1);
binary_heap.push(1);
- let _ = &vec[..].len();
+ &vec[..].len();
vec.len();
boxed_slice.len();
vec_deque.len();
binary_heap.len();
vec.len();
- let _ = &vec[..].len();
+ &vec[..].len();
vec_deque.len();
hash_map.len();
b_tree_map.len();
linked_list.len();
- let _ = &vec[..].len();
+ &vec[..].len();
vec.len();
vec_deque.len();
hash_set.len();
}
}
+#[allow(unused_must_use)]
fn main() {
let mut vec = vec![0, 1, 2, 3];
let mut boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]);
linked_list.push_back(1);
binary_heap.push(1);
- let _ = &vec[..].iter().count();
+ &vec[..].iter().count();
vec.iter().count();
boxed_slice.iter().count();
vec_deque.iter().count();
binary_heap.iter().count();
vec.iter_mut().count();
- let _ = &vec[..].iter_mut().count();
+ &vec[..].iter_mut().count();
vec_deque.iter_mut().count();
hash_map.iter_mut().count();
b_tree_map.iter_mut().count();
linked_list.iter_mut().count();
- let _ = &vec[..].into_iter().count();
+ &vec[..].into_iter().count();
vec.into_iter().count();
vec_deque.into_iter().count();
hash_set.into_iter().count();
error: called `.iter().count()` on a `slice`
- --> $DIR/iter_count.rs:53:14
+ --> $DIR/iter_count.rs:54:6
|
-LL | let _ = &vec[..].iter().count();
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
+LL | &vec[..].iter().count();
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
|
= note: `-D clippy::iter-count` implied by `-D warnings`
error: called `.iter().count()` on a `Vec`
- --> $DIR/iter_count.rs:54:5
+ --> $DIR/iter_count.rs:55:5
|
LL | vec.iter().count();
| ^^^^^^^^^^^^^^^^^^ help: try: `vec.len()`
error: called `.iter().count()` on a `slice`
- --> $DIR/iter_count.rs:55:5
+ --> $DIR/iter_count.rs:56:5
|
LL | boxed_slice.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice.len()`
error: called `.iter().count()` on a `VecDeque`
- --> $DIR/iter_count.rs:56:5
+ --> $DIR/iter_count.rs:57:5
|
LL | vec_deque.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()`
error: called `.iter().count()` on a `HashSet`
- --> $DIR/iter_count.rs:57:5
+ --> $DIR/iter_count.rs:58:5
|
LL | hash_set.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()`
error: called `.iter().count()` on a `HashMap`
- --> $DIR/iter_count.rs:58:5
+ --> $DIR/iter_count.rs:59:5
|
LL | hash_map.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()`
error: called `.iter().count()` on a `BTreeMap`
- --> $DIR/iter_count.rs:59:5
+ --> $DIR/iter_count.rs:60:5
|
LL | b_tree_map.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()`
error: called `.iter().count()` on a `BTreeSet`
- --> $DIR/iter_count.rs:60:5
+ --> $DIR/iter_count.rs:61:5
|
LL | b_tree_set.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()`
error: called `.iter().count()` on a `LinkedList`
- --> $DIR/iter_count.rs:61:5
+ --> $DIR/iter_count.rs:62:5
|
LL | linked_list.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()`
error: called `.iter().count()` on a `BinaryHeap`
- --> $DIR/iter_count.rs:62:5
+ --> $DIR/iter_count.rs:63:5
|
LL | binary_heap.iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()`
error: called `.iter_mut().count()` on a `Vec`
- --> $DIR/iter_count.rs:64:5
+ --> $DIR/iter_count.rs:65:5
|
LL | vec.iter_mut().count();
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()`
error: called `.iter_mut().count()` on a `slice`
- --> $DIR/iter_count.rs:65:14
+ --> $DIR/iter_count.rs:66:6
|
-LL | let _ = &vec[..].iter_mut().count();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
+LL | &vec[..].iter_mut().count();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
error: called `.iter_mut().count()` on a `VecDeque`
- --> $DIR/iter_count.rs:66:5
+ --> $DIR/iter_count.rs:67:5
|
LL | vec_deque.iter_mut().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()`
error: called `.iter_mut().count()` on a `HashMap`
- --> $DIR/iter_count.rs:67:5
+ --> $DIR/iter_count.rs:68:5
|
LL | hash_map.iter_mut().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()`
error: called `.iter_mut().count()` on a `BTreeMap`
- --> $DIR/iter_count.rs:68:5
+ --> $DIR/iter_count.rs:69:5
|
LL | b_tree_map.iter_mut().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()`
error: called `.iter_mut().count()` on a `LinkedList`
- --> $DIR/iter_count.rs:69:5
+ --> $DIR/iter_count.rs:70:5
|
LL | linked_list.iter_mut().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()`
error: called `.into_iter().count()` on a `slice`
- --> $DIR/iter_count.rs:71:14
+ --> $DIR/iter_count.rs:72:6
|
-LL | let _ = &vec[..].into_iter().count();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
+LL | &vec[..].into_iter().count();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()`
error: called `.into_iter().count()` on a `Vec`
- --> $DIR/iter_count.rs:72:5
+ --> $DIR/iter_count.rs:73:5
|
LL | vec.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()`
error: called `.into_iter().count()` on a `VecDeque`
- --> $DIR/iter_count.rs:73:5
+ --> $DIR/iter_count.rs:74:5
|
LL | vec_deque.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()`
error: called `.into_iter().count()` on a `HashSet`
- --> $DIR/iter_count.rs:74:5
+ --> $DIR/iter_count.rs:75:5
|
LL | hash_set.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()`
error: called `.into_iter().count()` on a `HashMap`
- --> $DIR/iter_count.rs:75:5
+ --> $DIR/iter_count.rs:76:5
|
LL | hash_map.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()`
error: called `.into_iter().count()` on a `BTreeMap`
- --> $DIR/iter_count.rs:76:5
+ --> $DIR/iter_count.rs:77:5
|
LL | b_tree_map.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()`
error: called `.into_iter().count()` on a `BTreeSet`
- --> $DIR/iter_count.rs:77:5
+ --> $DIR/iter_count.rs:78:5
|
LL | b_tree_set.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()`
error: called `.into_iter().count()` on a `LinkedList`
- --> $DIR/iter_count.rs:78:5
+ --> $DIR/iter_count.rs:79:5
|
LL | linked_list.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()`
error: called `.into_iter().count()` on a `BinaryHeap`
- --> $DIR/iter_count.rs:79:5
+ --> $DIR/iter_count.rs:80:5
|
LL | binary_heap.into_iter().count();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()`
-// edition:2018
-
#![warn(clippy::len_without_is_empty)]
#![allow(dead_code, unused)]
error: struct `PubOne` has a public `len` method, but no `is_empty` method
- --> $DIR/len_without_is_empty.rs:9:5
+ --> $DIR/len_without_is_empty.rs:7:5
|
LL | pub fn len(&self) -> isize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::len-without-is-empty` implied by `-D warnings`
error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` method
- --> $DIR/len_without_is_empty.rs:57:1
+ --> $DIR/len_without_is_empty.rs:55:1
|
LL | / pub trait PubTraitsToo {
LL | | fn len(&self) -> isize;
| |_^
error: struct `HasIsEmpty` has a public `len` method, but a private `is_empty` method
- --> $DIR/len_without_is_empty.rs:70:5
+ --> $DIR/len_without_is_empty.rs:68:5
|
LL | pub fn len(&self) -> isize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `is_empty` defined here
- --> $DIR/len_without_is_empty.rs:74:5
+ --> $DIR/len_without_is_empty.rs:72:5
|
LL | fn is_empty(&self) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: struct `HasWrongIsEmpty` has a public `len` method, but the `is_empty` method has an unexpected signature
- --> $DIR/len_without_is_empty.rs:82:5
+ --> $DIR/len_without_is_empty.rs:80:5
|
LL | pub fn len(&self) -> isize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `is_empty` defined here
- --> $DIR/len_without_is_empty.rs:86:5
+ --> $DIR/len_without_is_empty.rs:84:5
|
LL | pub fn is_empty(&self, x: u32) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature: `(&self) -> bool`
error: struct `MismatchedSelf` has a public `len` method, but the `is_empty` method has an unexpected signature
- --> $DIR/len_without_is_empty.rs:94:5
+ --> $DIR/len_without_is_empty.rs:92:5
|
LL | pub fn len(self) -> isize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `is_empty` defined here
- --> $DIR/len_without_is_empty.rs:98:5
+ --> $DIR/len_without_is_empty.rs:96:5
|
LL | pub fn is_empty(&self) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature: `(self) -> bool`
error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method
- --> $DIR/len_without_is_empty.rs:173:1
+ --> $DIR/len_without_is_empty.rs:171:1
|
LL | / pub trait DependsOnFoo: Foo {
LL | | fn len(&mut self) -> usize;
| |_^
error: struct `OptionalLen3` has a public `len` method, but the `is_empty` method has an unexpected signature
- --> $DIR/len_without_is_empty.rs:218:5
+ --> $DIR/len_without_is_empty.rs:216:5
|
LL | pub fn len(&self) -> usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `is_empty` defined here
- --> $DIR/len_without_is_empty.rs:223:5
+ --> $DIR/len_without_is_empty.rs:221:5
|
LL | pub fn is_empty(&self) -> Option<bool> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature: `(&self) -> bool`
error: struct `ResultLen` has a public `len` method, but the `is_empty` method has an unexpected signature
- --> $DIR/len_without_is_empty.rs:230:5
+ --> $DIR/len_without_is_empty.rs:228:5
|
LL | pub fn len(&self) -> Result<usize, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: `is_empty` defined here
- --> $DIR/len_without_is_empty.rs:235:5
+ --> $DIR/len_without_is_empty.rs:233:5
|
LL | pub fn is_empty(&self) -> Option<bool> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: expected signature: `(&self) -> bool` or `(&self) -> Result<bool>
error: this returns a `Result<_, ()>`
- --> $DIR/len_without_is_empty.rs:230:5
+ --> $DIR/len_without_is_empty.rs:228:5
|
LL | pub fn len(&self) -> Result<usize, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a custom `Error` type instead
error: this returns a `Result<_, ()>`
- --> $DIR/len_without_is_empty.rs:242:5
+ --> $DIR/len_without_is_empty.rs:240:5
|
LL | pub fn len(&self) -> Result<usize, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a custom `Error` type instead
error: this returns a `Result<_, ()>`
- --> $DIR/len_without_is_empty.rs:246:5
+ --> $DIR/len_without_is_empty.rs:244:5
|
LL | pub fn is_empty(&self) -> Result<bool, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= help: use a custom `Error` type instead
error: this returns a `Result<_, ()>`
- --> $DIR/len_without_is_empty.rs:253:5
+ --> $DIR/len_without_is_empty.rs:251:5
|
LL | pub fn len(&self) -> Result<usize, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#![warn(clippy::mixed_case_hex_literals)]
#![warn(clippy::zero_prefixed_literal)]
-#![allow(clippy::unseparated_literal_suffix)]
-#![allow(dead_code)]
+#![warn(clippy::unseparated_literal_suffix)]
+#![warn(clippy::separated_literal_suffix)]
+#![allow(dead_code, overflowing_literals)]
fn main() {
let ok1 = 0xABCD;
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:12:15
+ |
+LL | let ok4 = 0xab_cd_i32;
+ | ^^^^^^^^^^^ help: remove the underscore: `0xab_cdi32`
+ |
+ = note: `-D clippy::separated-literal-suffix` implied by `-D warnings`
+
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:13:15
+ |
+LL | let ok5 = 0xAB_CD_u32;
+ | ^^^^^^^^^^^ help: remove the underscore: `0xAB_CDu32`
+
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:14:15
+ |
+LL | let ok5 = 0xAB_CD_isize;
+ | ^^^^^^^^^^^^^ help: remove the underscore: `0xAB_CDisize`
+
error: inconsistent casing in hexadecimal literal
- --> $DIR/literals.rs:14:17
+ --> $DIR/literals.rs:15:17
|
LL | let fail1 = 0xabCD;
| ^^^^^^
|
= note: `-D clippy::mixed-case-hex-literals` implied by `-D warnings`
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:16:17
+ |
+LL | let fail2 = 0xabCD_u32;
+ | ^^^^^^^^^^ help: remove the underscore: `0xabCDu32`
+
error: inconsistent casing in hexadecimal literal
- --> $DIR/literals.rs:15:17
+ --> $DIR/literals.rs:16:17
|
LL | let fail2 = 0xabCD_u32;
| ^^^^^^^^^^
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:17:17
+ |
+LL | let fail2 = 0xabCD_isize;
+ | ^^^^^^^^^^^^ help: remove the underscore: `0xabCDisize`
+
error: inconsistent casing in hexadecimal literal
- --> $DIR/literals.rs:16:17
+ --> $DIR/literals.rs:17:17
|
LL | let fail2 = 0xabCD_isize;
| ^^^^^^^^^^^^
+error: integer type suffix should be separated by an underscore
+ --> $DIR/literals.rs:18:27
+ |
+LL | let fail_multi_zero = 000_123usize;
+ | ^^^^^^^^^^^^ help: add an underscore: `000_123_usize`
+ |
+ = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings`
+
error: this is a decimal constant
- --> $DIR/literals.rs:17:27
+ --> $DIR/literals.rs:18:27
|
LL | let fail_multi_zero = 000_123usize;
| ^^^^^^^^^^^^
LL | let fail_multi_zero = 0o123usize;
| ~~~~~~~~~~
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:21:16
+ |
+LL | let ok10 = 0_i64;
+ | ^^^^^ help: remove the underscore: `0i64`
+
error: this is a decimal constant
- --> $DIR/literals.rs:21:17
+ --> $DIR/literals.rs:22:17
|
LL | let fail8 = 0123;
| ^^^^
LL | let fail8 = 0o123;
| ~~~~~
+error: integer type suffix should not be separated by an underscore
+ --> $DIR/literals.rs:31:16
+ |
+LL | let ok17 = 0x123_4567_8901_usize;
+ | ^^^^^^^^^^^^^^^^^^^^^ help: remove the underscore: `0x123_4567_8901usize`
+
error: digits grouped inconsistently by underscores
- --> $DIR/literals.rs:33:18
+ --> $DIR/literals.rs:34:18
|
LL | let fail19 = 12_3456_21;
| ^^^^^^^^^^ help: consider: `12_345_621`
= note: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings`
error: digits grouped inconsistently by underscores
- --> $DIR/literals.rs:34:18
+ --> $DIR/literals.rs:35:18
|
LL | let fail22 = 3__4___23;
| ^^^^^^^^^ help: consider: `3_423`
error: digits grouped inconsistently by underscores
- --> $DIR/literals.rs:35:18
+ --> $DIR/literals.rs:36:18
|
LL | let fail23 = 3__16___23;
| ^^^^^^^^^^ help: consider: `31_623`
error: digits of hex or binary literal not grouped by four
- --> $DIR/literals.rs:37:18
+ --> $DIR/literals.rs:38:18
|
LL | let fail24 = 0xAB_ABC_AB;
| ^^^^^^^^^^^ help: consider: `0x0ABA_BCAB`
= note: `-D clippy::unusual-byte-groupings` implied by `-D warnings`
error: digits of hex or binary literal not grouped by four
- --> $DIR/literals.rs:38:18
+ --> $DIR/literals.rs:39:18
|
LL | let fail25 = 0b01_100_101;
| ^^^^^^^^^^^^ help: consider: `0b0110_0101`
-error: aborting due to 10 previous errors
+error: aborting due to 18 previous errors
-// compile-flags: --edition 2018
// aux-build:macro_rules.rs
// aux-build:macro_use_helper.rs
// aux-build:proc_macro_derive.rs
-// compile-flags: --edition 2018
// aux-build:macro_rules.rs
// aux-build:macro_use_helper.rs
// aux-build:proc_macro_derive.rs
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:19:5
+ --> $DIR/macro_use_imports.rs:18:5
|
LL | #[macro_use]
| ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};`
= note: `-D clippy::macro-use-imports` implied by `-D warnings`
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:25:5
+ --> $DIR/macro_use_imports.rs:20:5
|
LL | #[macro_use]
- | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:21:5
+ --> $DIR/macro_use_imports.rs:22:5
|
LL | #[macro_use]
- | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;`
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
error: `macro_use` attributes are no longer needed in the Rust 2018 edition
- --> $DIR/macro_use_imports.rs:23:5
+ --> $DIR/macro_use_imports.rs:24:5
|
LL | #[macro_use]
- | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};`
+ | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;`
error: aborting due to 4 previous errors
--- /dev/null
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+ let a = vec![1, 2, 3];
+ let c = Some(2);
+ if !a.is_empty()
+ && a.len() == 3
+ && c != None
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ {
+ panic!("qaqaq{:?}", a);
+ }
+ assert!(a.is_empty(), "qaqaq{:?}", a);
+ assert!(a.is_empty(), "qwqwq");
+ if a.len() == 3 {
+ println!("qwq");
+ println!("qwq");
+ println!("qwq");
+ }
+ if let Some(b) = c {
+ panic!("orz {}", b);
+ }
+ if a.len() == 3 {
+ panic!("qaqaq");
+ } else {
+ println!("qwq");
+ }
+ let b = vec![1, 2, 3];
+ assert!(!b.is_empty(), "panic1");
+ assert!(!(b.is_empty() && a.is_empty()), "panic2");
+ assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+ assert!(!(b.is_empty() || a.is_empty()), "panic4");
+ assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+}
--- /dev/null
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:22:5
+ |
+LL | / if !a.is_empty() {
+LL | | panic!("qaqaq{:?}", a);
+LL | | }
+ | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
+ |
+ = note: `-D clippy::manual-assert` implied by `-D warnings`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:25:5
+ |
+LL | / if !a.is_empty() {
+LL | | panic!("qwqwq");
+LL | | }
+ | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:42:5
+ |
+LL | / if b.is_empty() {
+LL | | panic!("panic1");
+LL | | }
+ | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:45:5
+ |
+LL | / if b.is_empty() && a.is_empty() {
+LL | | panic!("panic2");
+LL | | }
+ | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:48:5
+ |
+LL | / if a.is_empty() && !b.is_empty() {
+LL | | panic!("panic3");
+LL | | }
+ | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:51:5
+ |
+LL | / if b.is_empty() || a.is_empty() {
+LL | | panic!("panic4");
+LL | | }
+ | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:54:5
+ |
+LL | / if a.is_empty() || !b.is_empty() {
+LL | | panic!("panic5");
+LL | | }
+ | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+ let a = vec![1, 2, 3];
+ let c = Some(2);
+ if !a.is_empty()
+ && a.len() == 3
+ && c != None
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ {
+ panic!("qaqaq{:?}", a);
+ }
+ assert!(a.is_empty(), "qaqaq{:?}", a);
+ assert!(a.is_empty(), "qwqwq");
+ if a.len() == 3 {
+ println!("qwq");
+ println!("qwq");
+ println!("qwq");
+ }
+ if let Some(b) = c {
+ panic!("orz {}", b);
+ }
+ if a.len() == 3 {
+ panic!("qaqaq");
+ } else {
+ println!("qwq");
+ }
+ let b = vec![1, 2, 3];
+ assert!(!b.is_empty(), "panic1");
+ assert!(!(b.is_empty() && a.is_empty()), "panic2");
+ assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+ assert!(!(b.is_empty() || a.is_empty()), "panic4");
+ assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+}
--- /dev/null
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:22:5
+ |
+LL | / if !a.is_empty() {
+LL | | panic!("qaqaq{:?}", a);
+LL | | }
+ | |_____^ help: try: `assert!(a.is_empty(), "qaqaq{:?}", a);`
+ |
+ = note: `-D clippy::manual-assert` implied by `-D warnings`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:25:5
+ |
+LL | / if !a.is_empty() {
+LL | | panic!("qwqwq");
+LL | | }
+ | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:42:5
+ |
+LL | / if b.is_empty() {
+LL | | panic!("panic1");
+LL | | }
+ | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:45:5
+ |
+LL | / if b.is_empty() && a.is_empty() {
+LL | | panic!("panic2");
+LL | | }
+ | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:48:5
+ |
+LL | / if a.is_empty() && !b.is_empty() {
+LL | | panic!("panic3");
+LL | | }
+ | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:51:5
+ |
+LL | / if b.is_empty() || a.is_empty() {
+LL | | panic!("panic4");
+LL | | }
+ | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
+
+error: only a `panic!` in `if`-then statement
+ --> $DIR/manual_assert.rs:54:5
+ |
+LL | / if a.is_empty() || !b.is_empty() {
+LL | | panic!("panic5");
+LL | | }
+ | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
+
+error: aborting due to 7 previous errors
+
--- /dev/null
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+ let a = vec![1, 2, 3];
+ let c = Some(2);
+ if !a.is_empty()
+ && a.len() == 3
+ && c != None
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ {
+ panic!("qaqaq{:?}", a);
+ }
+ assert!(a.is_empty(), "qaqaq{:?}", a);
+ assert!(a.is_empty(), "qwqwq");
+ if a.len() == 3 {
+ println!("qwq");
+ println!("qwq");
+ println!("qwq");
+ }
+ if let Some(b) = c {
+ panic!("orz {}", b);
+ }
+ if a.len() == 3 {
+ panic!("qaqaq");
+ } else {
+ println!("qwq");
+ }
+ let b = vec![1, 2, 3];
+ assert!(!b.is_empty(), "panic1");
+ assert!(!(b.is_empty() && a.is_empty()), "panic2");
+ assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+ assert!(!(b.is_empty() || a.is_empty()), "panic4");
+ assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+}
--- /dev/null
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
+// run-rustfix
+#![warn(clippy::manual_assert)]
+
+fn main() {
+ let a = vec![1, 2, 3];
+ let c = Some(2);
+ if !a.is_empty()
+ && a.len() == 3
+ && c != None
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ && !a.is_empty()
+ && a.len() == 3
+ {
+ panic!("qaqaq{:?}", a);
+ }
+ if !a.is_empty() {
+ panic!("qaqaq{:?}", a);
+ }
+ if !a.is_empty() {
+ panic!("qwqwq");
+ }
+ if a.len() == 3 {
+ println!("qwq");
+ println!("qwq");
+ println!("qwq");
+ }
+ if let Some(b) = c {
+ panic!("orz {}", b);
+ }
+ if a.len() == 3 {
+ panic!("qaqaq");
+ } else {
+ println!("qwq");
+ }
+ let b = vec![1, 2, 3];
+ if b.is_empty() {
+ panic!("panic1");
+ }
+ if b.is_empty() && a.is_empty() {
+ panic!("panic2");
+ }
+ if a.is_empty() && !b.is_empty() {
+ panic!("panic3");
+ }
+ if b.is_empty() || a.is_empty() {
+ panic!("panic4");
+ }
+ if a.is_empty() || !b.is_empty() {
+ panic!("panic5");
+ }
+}
// run-rustfix
-// edition:2018
#![warn(clippy::manual_async_fn)]
#![allow(unused)]
// run-rustfix
-// edition:2018
#![warn(clippy::manual_async_fn)]
#![allow(unused)]
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:8:1
+ --> $DIR/manual_async_fn.rs:7:1
|
LL | fn fut() -> impl Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:13:1
+ --> $DIR/manual_async_fn.rs:12:1
|
LL | fn fut2() ->impl Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:18:1
+ --> $DIR/manual_async_fn.rs:17:1
|
LL | fn fut3()-> impl Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:22:1
+ --> $DIR/manual_async_fn.rs:21:1
|
LL | fn empty_fut() -> impl Future<Output = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:27:1
+ --> $DIR/manual_async_fn.rs:26:1
|
LL | fn empty_fut2() ->impl Future<Output = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:32:1
+ --> $DIR/manual_async_fn.rs:31:1
|
LL | fn empty_fut3()-> impl Future<Output = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:36:1
+ --> $DIR/manual_async_fn.rs:35:1
|
LL | fn core_fut() -> impl core::future::Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:58:5
+ --> $DIR/manual_async_fn.rs:57:5
|
LL | fn inh_fut() -> impl Future<Output = i32> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:93:1
+ --> $DIR/manual_async_fn.rs:92:1
|
LL | fn elided(_: &i32) -> impl Future<Output = i32> + '_ {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ~~~~~~
error: this function can be simplified using the `async fn` syntax
- --> $DIR/manual_async_fn.rs:102:1
+ --> $DIR/manual_async_fn.rs:101:1
|
LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a + 'b {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-// edition:2018
// run-rustfix
#![warn(clippy::manual_map)]
-// edition:2018
// run-rustfix
#![warn(clippy::manual_map)]
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:15:5
+ --> $DIR/manual_map_option.rs:14:5
|
LL | / match Some(0) {
LL | | Some(_) => Some(2),
= note: `-D clippy::manual-map` implied by `-D warnings`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:20:5
+ --> $DIR/manual_map_option.rs:19:5
|
LL | / match Some(0) {
LL | | Some(x) => Some(x + 1),
| |_____^ help: try this: `Some(0).map(|x| x + 1)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:25:5
+ --> $DIR/manual_map_option.rs:24:5
|
LL | / match Some("") {
LL | | Some(x) => Some(x.is_empty()),
| |_____^ help: try this: `Some("").map(|x| x.is_empty())`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:30:5
+ --> $DIR/manual_map_option.rs:29:5
|
LL | / if let Some(x) = Some(0) {
LL | | Some(!x)
| |_____^ help: try this: `Some(0).map(|x| !x)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:37:5
+ --> $DIR/manual_map_option.rs:36:5
|
LL | / match Some(0) {
LL | | Some(x) => { Some(std::convert::identity(x)) }
| |_____^ help: try this: `Some(0).map(std::convert::identity)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:42:5
+ --> $DIR/manual_map_option.rs:41:5
|
LL | / match Some(&String::new()) {
LL | | Some(x) => Some(str::len(x)),
| |_____^ help: try this: `Some(&String::new()).map(|x| str::len(x))`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:52:5
+ --> $DIR/manual_map_option.rs:51:5
|
LL | / match &Some([0, 1]) {
LL | | Some(x) => Some(x[0]),
| |_____^ help: try this: `Some([0, 1]).as_ref().map(|x| x[0])`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:57:5
+ --> $DIR/manual_map_option.rs:56:5
|
LL | / match &Some(0) {
LL | | &Some(x) => Some(x * 2),
| |_____^ help: try this: `Some(0).map(|x| x * 2)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:62:5
+ --> $DIR/manual_map_option.rs:61:5
|
LL | / match Some(String::new()) {
LL | | Some(ref x) => Some(x.is_empty()),
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:67:5
+ --> $DIR/manual_map_option.rs:66:5
|
LL | / match &&Some(String::new()) {
LL | | Some(x) => Some(x.len()),
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:72:5
+ --> $DIR/manual_map_option.rs:71:5
|
LL | / match &&Some(0) {
LL | | &&Some(x) => Some(x + x),
| |_____^ help: try this: `Some(0).map(|x| x + x)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:85:9
+ --> $DIR/manual_map_option.rs:84:9
|
LL | / match &mut Some(String::new()) {
LL | | Some(x) => Some(x.push_str("")),
| |_________^ help: try this: `Some(String::new()).as_mut().map(|x| x.push_str(""))`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:91:5
+ --> $DIR/manual_map_option.rs:90:5
|
LL | / match &mut Some(String::new()) {
LL | | Some(ref x) => Some(x.len()),
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.len())`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:96:5
+ --> $DIR/manual_map_option.rs:95:5
|
LL | / match &mut &Some(String::new()) {
LL | | Some(x) => Some(x.is_empty()),
| |_____^ help: try this: `Some(String::new()).as_ref().map(|x| x.is_empty())`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:101:5
+ --> $DIR/manual_map_option.rs:100:5
|
LL | / match Some((0, 1, 2)) {
LL | | Some((x, y, z)) => Some(x + y + z),
| |_____^ help: try this: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:106:5
+ --> $DIR/manual_map_option.rs:105:5
|
LL | / match Some([1, 2, 3]) {
LL | | Some([first, ..]) => Some(first),
| |_____^ help: try this: `Some([1, 2, 3]).map(|[first, ..]| first)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:111:5
+ --> $DIR/manual_map_option.rs:110:5
|
LL | / match &Some((String::new(), "test")) {
LL | | Some((x, y)) => Some((y, x)),
| |_____^ help: try this: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:169:5
+ --> $DIR/manual_map_option.rs:168:5
|
LL | / match Some(0) {
LL | | Some(x) => Some(vec![x]),
| |_____^ help: try this: `Some(0).map(|x| vec![x])`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:174:5
+ --> $DIR/manual_map_option.rs:173:5
|
LL | / match option_env!("") {
LL | | Some(x) => Some(String::from(x)),
| |_____^ help: try this: `option_env!("").map(String::from)`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:194:12
+ --> $DIR/manual_map_option.rs:193:12
|
LL | } else if let Some(x) = Some(0) {
| ____________^
| |_____^ help: try this: `{ Some(0).map(|x| x + 1) }`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option.rs:202:12
+ --> $DIR/manual_map_option.rs:201:12
|
LL | } else if let Some(x) = Some(0) {
| ____________^
+#![allow(clippy::too_many_arguments, clippy::diverging_sub_expression)]
#![warn(clippy::many_single_char_names)]
fn bla() {
error: 5 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:4:9
+ --> $DIR/many_single_char_names.rs:5:9
|
LL | let a: i32;
| ^
= note: `-D clippy::many-single-char-names` implied by `-D warnings`
error: 6 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:4:9
+ --> $DIR/many_single_char_names.rs:5:9
|
LL | let a: i32;
| ^
| ^
error: 5 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:4:9
+ --> $DIR/many_single_char_names.rs:5:9
|
LL | let a: i32;
| ^
| ^
error: 8 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:29:13
+ --> $DIR/many_single_char_names.rs:30:13
|
LL | fn bindings(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) {}
| ^ ^ ^ ^ ^ ^ ^ ^
error: 8 bindings with single-character names in scope
- --> $DIR/many_single_char_names.rs:32:10
+ --> $DIR/many_single_char_names.rs:33:10
|
LL | let (a, b, c, d, e, f, g, h): (bool, bool, bool, bool, bool, bool, bool, bool) = unimplemented!();
| ^ ^ ^ ^ ^ ^ ^ ^
_ => (),
}
+ // Issue #7829
+ match 0 {
+ -1..=1 => (),
+ -2..=2 => (),
+ _ => (),
+ }
+
if let None = Some(42) {
// nothing
} else if let None = Some(42) {
#![warn(clippy::match_ref_pats)]
-#![allow(clippy::equatable_if_let)]
+#![allow(clippy::equatable_if_let, clippy::enum_variant_names)]
fn ref_pats() {
{
}
}
+fn non_alphabetic() {
+ let var = "~!@#$%^&*()-_=+FOO";
+
+ match var.to_ascii_lowercase().as_str() {
+ "1234567890" => {},
+ "~!@#$%^&*()-_=+foo" => {},
+ "\n\r\t\x7F" => {},
+ _ => {},
+ }
+}
+
+fn unicode_cased() {
+ let var = "ВОДЫ";
+
+ match var.to_lowercase().as_str() {
+ "水" => {},
+ "νερό" => {},
+ "воды" => {},
+ "물" => {},
+ _ => {},
+ }
+}
+
+fn titlecase() {
+ let var = "BarDz";
+
+ match var.to_lowercase().as_str() {
+ "foolj" => {},
+ "bardz" => {},
+ _ => {},
+ }
+}
+
+fn no_case_equivalent() {
+ let var = "barʁ";
+
+ match var.to_uppercase().as_str() {
+ "FOOɕ" => {},
+ "BARʁ" => {},
+ _ => {},
+ }
+}
+
fn addrof_unary_match() {
let var = "BAR";
}
}
+fn non_alphabetic_mismatch() {
+ let var = "~!@#$%^&*()-_=+FOO";
+
+ match var.to_ascii_lowercase().as_str() {
+ "1234567890" => {},
+ "~!@#$%^&*()-_=+Foo" => {},
+ "\n\r\t\x7F" => {},
+ _ => {},
+ }
+}
+
+fn unicode_cased_mismatch() {
+ let var = "ВОДЫ";
+
+ match var.to_lowercase().as_str() {
+ "水" => {},
+ "νερό" => {},
+ "Воды" => {},
+ "물" => {},
+ _ => {},
+ }
+}
+
+fn titlecase_mismatch() {
+ let var = "BarDz";
+
+ match var.to_lowercase().as_str() {
+ "foolj" => {},
+ "barDz" => {},
+ _ => {},
+ }
+}
+
+fn no_case_equivalent_mismatch() {
+ let var = "barʁ";
+
+ match var.to_uppercase().as_str() {
+ "FOOɕ" => {},
+ "bARʁ" => {},
+ _ => {},
+ }
+}
+
fn addrof_unary_match_mismatch() {
let var = "BAR";
error: this `match` arm has a differing case than its expression
- --> $DIR/match_str_case_mismatch.rs:68:9
+ --> $DIR/match_str_case_mismatch.rs:111:9
|
LL | "Bar" => {},
| ^^^^^
| ~~~~~
error: this `match` arm has a differing case than its expression
- --> $DIR/match_str_case_mismatch.rs:78:9
+ --> $DIR/match_str_case_mismatch.rs:121:9
+ |
+LL | "~!@#$%^&*()-_=+Foo" => {},
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider changing the case of this arm to respect `to_ascii_lowercase`
+ |
+LL | "~!@#$%^&*()-_=+foo" => {},
+ | ~~~~~~~~~~~~~~~~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:133:9
+ |
+LL | "Воды" => {},
+ | ^^^^^^
+ |
+help: consider changing the case of this arm to respect `to_lowercase`
+ |
+LL | "воды" => {},
+ | ~~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:144:9
+ |
+LL | "barDz" => {},
+ | ^^^^^^
+ |
+help: consider changing the case of this arm to respect `to_lowercase`
+ |
+LL | "bardz" => {},
+ | ~~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:154:9
+ |
+LL | "bARʁ" => {},
+ | ^^^^^^
+ |
+help: consider changing the case of this arm to respect `to_uppercase`
+ |
+LL | "BARʁ" => {},
+ | ~~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:164:9
|
LL | "Bar" => {},
| ^^^^^
| ~~~~~
error: this `match` arm has a differing case than its expression
- --> $DIR/match_str_case_mismatch.rs:93:9
+ --> $DIR/match_str_case_mismatch.rs:179:9
|
LL | "bAR" => {},
| ^^^^^
LL | "BAR" => {},
| ~~~~~
-error: aborting due to 3 previous errors
+error: aborting due to 7 previous errors
--- /dev/null
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:14:9
+ |
+LL | Err(_) => panic!("err"),
+ | ^^^^^^
+ |
+ = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:20:9
+ |
+LL | Err(_) => panic!(),
+ | ^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:26:9
+ |
+LL | Err(_) => {
+ | ^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_e)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:34:9
+ |
+LL | Err(_e) => panic!(),
+ | ^^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:14:9
+ |
+LL | Err(_) => panic!("err"),
+ | ^^^^^^
+ |
+ = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:20:9
+ |
+LL | Err(_) => panic!(),
+ | ^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:26:9
+ |
+LL | Err(_) => {
+ | ^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: `Err(_e)` matches all errors
+ --> $DIR/match_wild_err_arm.rs:34:9
+ |
+LL | Err(_e) => panic!(),
+ | ^^^^^^^
+ |
+ = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
+
+error: aborting due to 4 previous errors
+
+// revisions: edition2018 edition2021
+// [edition2018] edition:2018
+// [edition2021] edition:2021
#![feature(exclusive_range_pattern)]
#![allow(clippy::match_same_arms)]
#![warn(clippy::match_wild_err_arm)]
+++ /dev/null
-error: `Err(_)` matches all errors
- --> $DIR/match_wild_err_arm.rs:11:9
- |
-LL | Err(_) => panic!("err"),
- | ^^^^^^
- |
- = note: `-D clippy::match-wild-err-arm` implied by `-D warnings`
- = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: `Err(_)` matches all errors
- --> $DIR/match_wild_err_arm.rs:17:9
- |
-LL | Err(_) => panic!(),
- | ^^^^^^
- |
- = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: `Err(_)` matches all errors
- --> $DIR/match_wild_err_arm.rs:23:9
- |
-LL | Err(_) => {
- | ^^^^^^
- |
- = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: `Err(_e)` matches all errors
- --> $DIR/match_wild_err_arm.rs:31:9
- |
-LL | Err(_e) => panic!(),
- | ^^^^^^^
- |
- = note: match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable
-
-error: aborting due to 4 previous errors
-
// aux-build:option_helpers.rs
-// edition:2018
#![warn(clippy::all, clippy::pedantic)]
#![allow(
error: methods called `new` usually return `Self`
- --> $DIR/methods.rs:105:5
+ --> $DIR/methods.rs:104:5
|
LL | / fn new() -> i32 {
LL | | 0
= note: `-D clippy::new-ret-no-self` implied by `-D warnings`
error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
- --> $DIR/methods.rs:126:13
+ --> $DIR/methods.rs:125:13
|
LL | let _ = v.iter().filter(|&x| {
| _____________^
// injected intrinsics by the compiler.
#![allow(dead_code)]
#![feature(global_asm)]
-
//! Some garbage docs for the crate here
#![doc = "More garbage"]
}
/// dox
pub mod public_interface {
- pub use internal_impl::documented as foo;
- pub use internal_impl::globbed::*;
- pub use internal_impl::undocumented1 as bar;
- pub use internal_impl::{documented, undocumented2};
+ pub use crate::internal_impl::documented as foo;
+ pub use crate::internal_impl::globbed::*;
+ pub use crate::internal_impl::undocumented1 as bar;
+ pub use crate::internal_impl::{documented, undocumented2};
}
fn main() {}
error: missing documentation for a type alias
- --> $DIR/missing-doc.rs:10:1
+ --> $DIR/missing-doc.rs:9:1
|
LL | type Typedef = String;
| ^^^^^^^^^^^^^^^^^^^^^^
= note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
error: missing documentation for a type alias
- --> $DIR/missing-doc.rs:11:1
+ --> $DIR/missing-doc.rs:10:1
|
LL | pub type PubTypedef = String;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:13:1
+ --> $DIR/missing-doc.rs:12:1
|
LL | mod module_no_dox {}
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:14:1
+ --> $DIR/missing-doc.rs:13:1
|
LL | pub mod pub_module_no_dox {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:18:1
+ --> $DIR/missing-doc.rs:17:1
|
LL | pub fn foo2() {}
| ^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:19:1
+ --> $DIR/missing-doc.rs:18:1
|
LL | fn foo3() {}
| ^^^^^^^^^^^^
error: missing documentation for an enum
- --> $DIR/missing-doc.rs:33:1
+ --> $DIR/missing-doc.rs:32:1
|
LL | / enum Baz {
LL | | BazA { a: isize, b: isize },
| |_^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:34:5
+ --> $DIR/missing-doc.rs:33:5
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:34:12
+ --> $DIR/missing-doc.rs:33:12
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:34:22
+ --> $DIR/missing-doc.rs:33:22
|
LL | BazA { a: isize, b: isize },
| ^^^^^^^^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:35:5
+ --> $DIR/missing-doc.rs:34:5
|
LL | BarB,
| ^^^^
error: missing documentation for an enum
- --> $DIR/missing-doc.rs:38:1
+ --> $DIR/missing-doc.rs:37:1
|
LL | / pub enum PubBaz {
LL | | PubBazA { a: isize },
| |_^
error: missing documentation for a variant
- --> $DIR/missing-doc.rs:39:5
+ --> $DIR/missing-doc.rs:38:5
|
LL | PubBazA { a: isize },
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/missing-doc.rs:39:15
+ --> $DIR/missing-doc.rs:38:15
|
LL | PubBazA { a: isize },
| ^^^^^^^^
error: missing documentation for a constant
- --> $DIR/missing-doc.rs:59:1
+ --> $DIR/missing-doc.rs:58:1
|
LL | const FOO: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^
error: missing documentation for a constant
- --> $DIR/missing-doc.rs:66:1
+ --> $DIR/missing-doc.rs:65:1
|
LL | pub const FOO4: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a static
- --> $DIR/missing-doc.rs:68:1
+ --> $DIR/missing-doc.rs:67:1
|
LL | static BAR: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a static
- --> $DIR/missing-doc.rs:75:1
+ --> $DIR/missing-doc.rs:74:1
|
LL | pub static BAR4: u32 = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a module
- --> $DIR/missing-doc.rs:77:1
+ --> $DIR/missing-doc.rs:76:1
|
LL | / mod internal_impl {
LL | | /// dox
| |_^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:80:5
+ --> $DIR/missing-doc.rs:79:5
|
LL | pub fn undocumented1() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:81:5
+ --> $DIR/missing-doc.rs:80:5
|
LL | pub fn undocumented2() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:82:5
+ --> $DIR/missing-doc.rs:81:5
|
LL | fn undocumented3() {}
| ^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:87:9
+ --> $DIR/missing-doc.rs:86:9
|
LL | pub fn also_undocumented1() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/missing-doc.rs:88:9
+ --> $DIR/missing-doc.rs:87:9
|
LL | fn also_undocumented2() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
#![warn(clippy::missing_panics_doc)]
#![allow(clippy::option_map_unit_fn)]
-
fn main() {}
/// This needs to be documented
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:7:1
+ --> $DIR/missing_panics_doc.rs:6:1
|
LL | / pub fn unwrap() {
LL | | let result = Err("Hi");
|
= note: `-D clippy::missing-panics-doc` implied by `-D warnings`
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:9:5
+ --> $DIR/missing_panics_doc.rs:8:5
|
LL | result.unwrap()
| ^^^^^^^^^^^^^^^
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:13:1
+ --> $DIR/missing_panics_doc.rs:12:1
|
LL | / pub fn panic() {
LL | | panic!("This function panics")
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:14:5
+ --> $DIR/missing_panics_doc.rs:13:5
|
LL | panic!("This function panics")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:18:1
+ --> $DIR/missing_panics_doc.rs:17:1
|
LL | / pub fn todo() {
LL | | todo!()
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:19:5
+ --> $DIR/missing_panics_doc.rs:18:5
|
LL | todo!()
| ^^^^^^^
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:23:1
+ --> $DIR/missing_panics_doc.rs:22:1
|
LL | / pub fn inner_body(opt: Option<u32>) {
LL | | opt.map(|x| {
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:26:13
+ --> $DIR/missing_panics_doc.rs:25:13
|
LL | panic!()
| ^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:32:1
+ --> $DIR/missing_panics_doc.rs:31:1
|
LL | / pub fn unreachable_and_panic() {
LL | | if true { unreachable!() } else { panic!() }
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:33:39
+ --> $DIR/missing_panics_doc.rs:32:39
|
LL | if true { unreachable!() } else { panic!() }
| ^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:37:1
+ --> $DIR/missing_panics_doc.rs:36:1
|
LL | / pub fn assert_eq() {
LL | | let x = 0;
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:39:5
+ --> $DIR/missing_panics_doc.rs:38:5
|
LL | assert_eq!(x, 0);
| ^^^^^^^^^^^^^^^^
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: docs for function which may panic missing `# Panics` section
- --> $DIR/missing_panics_doc.rs:43:1
+ --> $DIR/missing_panics_doc.rs:42:1
|
LL | / pub fn assert_ne() {
LL | | let x = 0;
| |_^
|
note: first possible panic found here
- --> $DIR/missing_panics_doc.rs:45:5
+ --> $DIR/missing_panics_doc.rs:44:5
|
LL | assert_ne!(x, 0);
| ^^^^^^^^^^^^^^^^
#![allow(
dead_code,
unused_variables,
+ overflowing_literals,
clippy::excessive_precision,
clippy::inconsistent_digit_grouping
)]
let fail25 = 1E2_f32;
let fail26 = 43E7_f64;
let fail27 = 243E17_f32;
- #[allow(overflowing_literals)]
let fail28 = 241_251_235E723_f64;
let ok29 = 42279.911_32;
#![allow(
dead_code,
unused_variables,
+ overflowing_literals,
clippy::excessive_precision,
clippy::inconsistent_digit_grouping
)]
let fail25 = 1E2_32;
let fail26 = 43E7_64;
let fail27 = 243E17_32;
- #[allow(overflowing_literals)]
let fail28 = 241251235E723_64;
let ok29 = 42279.911_32;
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:11:18
+ --> $DIR/mistyped_literal_suffix.rs:12:18
|
LL | let fail14 = 2_32;
| ^^^^ help: did you mean to write: `2_i32`
= note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:12:18
+ --> $DIR/mistyped_literal_suffix.rs:13:18
|
LL | let fail15 = 4_64;
| ^^^^ help: did you mean to write: `4_i64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:13:18
+ --> $DIR/mistyped_literal_suffix.rs:14:18
|
LL | let fail16 = 7_8; //
| ^^^ help: did you mean to write: `7_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:14:18
+ --> $DIR/mistyped_literal_suffix.rs:15:18
|
LL | let fail17 = 23_16; //
| ^^^^^ help: did you mean to write: `23_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:17:18
+ --> $DIR/mistyped_literal_suffix.rs:18:18
|
LL | let fail20 = 2__8; //
| ^^^^ help: did you mean to write: `2_i8`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:18:18
+ --> $DIR/mistyped_literal_suffix.rs:19:18
|
LL | let fail21 = 4___16; //
| ^^^^^^ help: did you mean to write: `4_i16`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:21:18
+ --> $DIR/mistyped_literal_suffix.rs:22:18
|
LL | let fail25 = 1E2_32;
| ^^^^^^ help: did you mean to write: `1E2_f32`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:22:18
+ --> $DIR/mistyped_literal_suffix.rs:23:18
|
LL | let fail26 = 43E7_64;
| ^^^^^^^ help: did you mean to write: `43E7_f64`
error: mistyped literal suffix
- --> $DIR/mistyped_literal_suffix.rs:23:18
+ --> $DIR/mistyped_literal_suffix.rs:24:18
|
LL | let fail27 = 243E17_32;
| ^^^^^^^^^ help: did you mean to write: `243E17_f32`
// fn call_with_mut_self<'life0>(self: &'life0 mut Self) {}
#[rename_my_lifetimes]
impl T2 for S2 {
+ #[allow(clippy::needless_lifetimes)]
fn call_with_mut_self(self: &mut Self) {}
}
}
error: the type of the `self` parameter does not need to be arbitrary
- --> $DIR/needless_arbitrary_self_type_unfixable.rs:41:31
+ --> $DIR/needless_arbitrary_self_type_unfixable.rs:42:31
|
LL | fn call_with_mut_self(self: &mut Self) {}
| ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'_ mut self`
-// edition:2018
// FIXME: run-rustfix waiting on multi-span suggestions
#![warn(clippy::needless_borrow)]
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:60:14
+ --> $DIR/needless_borrow_pat.rs:59:14
|
LL | Some(ref x) => x,
| ^^^^^ help: try this: `x`
= note: `-D clippy::needless-borrow` implied by `-D warnings`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:66:14
+ --> $DIR/needless_borrow_pat.rs:65:14
|
LL | Some(ref x) => *x,
| ^^^^^
| ~ ~
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:72:14
+ --> $DIR/needless_borrow_pat.rs:71:14
|
LL | Some(ref x) => {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:82:14
+ --> $DIR/needless_borrow_pat.rs:81:14
|
LL | Some(ref x) => m1!(x),
| ^^^^^ help: try this: `x`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:87:15
+ --> $DIR/needless_borrow_pat.rs:86:15
|
LL | let _ = |&ref x: &&String| {
| ^^^^^ help: try this: `x`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:92:10
+ --> $DIR/needless_borrow_pat.rs:91:10
|
LL | let (ref y,) = (&x,);
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:102:14
+ --> $DIR/needless_borrow_pat.rs:101:14
|
LL | Some(ref x) => x.0,
| ^^^^^ help: try this: `x`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:112:14
+ --> $DIR/needless_borrow_pat.rs:111:14
|
LL | E::A(ref x) | E::B(ref x) => *x,
| ^^^^^ ^^^^^
| ~ ~ ~
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:118:21
+ --> $DIR/needless_borrow_pat.rs:117:21
|
LL | if let Some(ref x) = Some(&String::new());
| ^^^^^ help: try this: `x`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:126:12
+ --> $DIR/needless_borrow_pat.rs:125:12
|
LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:133:11
+ --> $DIR/needless_borrow_pat.rs:132:11
|
LL | fn f(&ref x: &&String) {
| ^^^^^ help: try this: `x`
error: this pattern creates a reference to a reference
- --> $DIR/needless_borrow_pat.rs:141:11
+ --> $DIR/needless_borrow_pat.rs:140:11
|
LL | fn f(&ref x: &&String) {
| ^^^^^
};
}
+#[allow(clippy::nonminimal_bool)]
fn main() {
let mut i = 1;
while i < 10 {
error: this `else` block is redundant
- --> $DIR/needless_continue.rs:28:16
+ --> $DIR/needless_continue.rs:29:16
|
LL | } else {
| ________________^
}
error: there is no need for an explicit `else` block for this `if` expression
- --> $DIR/needless_continue.rs:43:9
+ --> $DIR/needless_continue.rs:44:9
|
LL | / if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 {
LL | | continue;
}
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:56:9
+ --> $DIR/needless_continue.rs:57:9
|
LL | continue; // should lint here
| ^^^^^^^^^
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:63:9
+ --> $DIR/needless_continue.rs:64:9
|
LL | continue; // should lint here
| ^^^^^^^^^
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:70:9
+ --> $DIR/needless_continue.rs:71:9
|
LL | continue // should lint here
| ^^^^^^^^
= help: consider dropping the `continue` expression
error: this `continue` expression is redundant
- --> $DIR/needless_continue.rs:78:9
+ --> $DIR/needless_continue.rs:79:9
|
LL | continue // should lint here
| ^^^^^^^^
= help: consider dropping the `continue` expression
error: this `else` block is redundant
- --> $DIR/needless_continue.rs:128:24
+ --> $DIR/needless_continue.rs:129:24
|
LL | } else {
| ________________________^
}
error: there is no need for an explicit `else` block for this `if` expression
- --> $DIR/needless_continue.rs:134:17
+ --> $DIR/needless_continue.rs:135:17
|
LL | / if condition() {
LL | | continue; // should lint here
x
}
+// No error; multiple input refs
+async fn func<'a>(args: &[&'a str]) -> Option<&'a str> {
+ args.get(0).cloned()
+}
+
// No error; static involved.
fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
x
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:45:1
+ --> $DIR/needless_lifetimes.rs:50:1
|
LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:50:1
+ --> $DIR/needless_lifetimes.rs:55:1
|
LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:62:1
+ --> $DIR/needless_lifetimes.rs:67:1
|
LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:86:1
+ --> $DIR/needless_lifetimes.rs:91:1
|
LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:116:5
+ --> $DIR/needless_lifetimes.rs:121:5
|
LL | fn self_and_out<'s>(&'s self) -> &'s u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:125:5
+ --> $DIR/needless_lifetimes.rs:130:5
|
LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:144:1
+ --> $DIR/needless_lifetimes.rs:149:1
|
LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:174:1
+ --> $DIR/needless_lifetimes.rs:179:1
|
LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:180:1
+ --> $DIR/needless_lifetimes.rs:185:1
|
LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:199:1
+ --> $DIR/needless_lifetimes.rs:204:1
|
LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:207:1
+ --> $DIR/needless_lifetimes.rs:212:1
|
LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:243:1
+ --> $DIR/needless_lifetimes.rs:248:1
|
LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:250:9
+ --> $DIR/needless_lifetimes.rs:255:9
|
LL | fn needless_lt<'a>(x: &'a u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:254:9
+ --> $DIR/needless_lifetimes.rs:259:9
|
LL | fn needless_lt<'a>(_x: &'a u8) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:267:9
+ --> $DIR/needless_lifetimes.rs:272:9
|
LL | fn baz<'a>(&'a self) -> impl Foo + 'a {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:296:5
+ --> $DIR/needless_lifetimes.rs:301:5
|
LL | fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:299:5
+ --> $DIR/needless_lifetimes.rs:304:5
|
LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:308:5
+ --> $DIR/needless_lifetimes.rs:313:5
|
LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:320:5
+ --> $DIR/needless_lifetimes.rs:325:5
|
LL | fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:335:5
+ --> $DIR/needless_lifetimes.rs:340:5
|
LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:348:5
+ --> $DIR/needless_lifetimes.rs:353:5
|
LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
- --> $DIR/needless_lifetimes.rs:351:5
+ --> $DIR/needless_lifetimes.rs:356:5
|
LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// run-rustfix
-// edition:2018
#![feature(let_else)]
#![allow(unused)]
// run-rustfix
-// edition:2018
#![feature(let_else)]
#![allow(unused)]
error: unneeded `return` statement
- --> $DIR/needless_return.rs:25:5
+ --> $DIR/needless_return.rs:24:5
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
= note: `-D clippy::needless-return` implied by `-D warnings`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:29:5
+ --> $DIR/needless_return.rs:28:5
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:34:9
+ --> $DIR/needless_return.rs:33:9
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:36:9
+ --> $DIR/needless_return.rs:35:9
|
LL | return false;
| ^^^^^^^^^^^^^ help: remove `return`: `false`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:42:17
+ --> $DIR/needless_return.rs:41:17
|
LL | true => return false,
| ^^^^^^^^^^^^ help: remove `return`: `false`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:44:13
+ --> $DIR/needless_return.rs:43:13
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:51:9
+ --> $DIR/needless_return.rs:50:9
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:53:16
+ --> $DIR/needless_return.rs:52:16
|
LL | let _ = || return true;
| ^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:61:5
+ --> $DIR/needless_return.rs:60:5
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:66:9
+ --> $DIR/needless_return.rs:65:9
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:68:9
+ --> $DIR/needless_return.rs:67:9
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:75:14
+ --> $DIR/needless_return.rs:74:14
|
LL | _ => return,
| ^^^^^^ help: replace `return` with an empty block: `{}`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:90:9
+ --> $DIR/needless_return.rs:89:9
|
LL | return String::from("test");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:92:9
+ --> $DIR/needless_return.rs:91:9
|
LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:113:32
+ --> $DIR/needless_return.rs:112:32
|
LL | bar.unwrap_or_else(|_| return)
| ^^^^^^ help: replace `return` with an empty block: `{}`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:118:13
+ --> $DIR/needless_return.rs:117:13
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:120:20
+ --> $DIR/needless_return.rs:119:20
|
LL | let _ = || return;
| ^^^^^^ help: replace `return` with an empty block: `{}`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:126:32
+ --> $DIR/needless_return.rs:125:32
|
LL | res.unwrap_or_else(|_| return Foo)
| ^^^^^^^^^^ help: remove `return`: `Foo`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:135:5
+ --> $DIR/needless_return.rs:134:5
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:139:5
+ --> $DIR/needless_return.rs:138:5
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:144:9
+ --> $DIR/needless_return.rs:143:9
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:146:9
+ --> $DIR/needless_return.rs:145:9
|
LL | return false;
| ^^^^^^^^^^^^^ help: remove `return`: `false`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:152:17
+ --> $DIR/needless_return.rs:151:17
|
LL | true => return false,
| ^^^^^^^^^^^^ help: remove `return`: `false`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:154:13
+ --> $DIR/needless_return.rs:153:13
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:161:9
+ --> $DIR/needless_return.rs:160:9
|
LL | return true;
| ^^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:163:16
+ --> $DIR/needless_return.rs:162:16
|
LL | let _ = || return true;
| ^^^^^^^^^^^ help: remove `return`: `true`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:171:5
+ --> $DIR/needless_return.rs:170:5
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:176:9
+ --> $DIR/needless_return.rs:175:9
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:178:9
+ --> $DIR/needless_return.rs:177:9
|
LL | return;
| ^^^^^^^ help: remove `return`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:185:14
+ --> $DIR/needless_return.rs:184:14
|
LL | _ => return,
| ^^^^^^ help: replace `return` with an empty block: `{}`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:200:9
+ --> $DIR/needless_return.rs:199:9
|
LL | return String::from("test");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::from("test")`
error: unneeded `return` statement
- --> $DIR/needless_return.rs:202:9
+ --> $DIR/needless_return.rs:201:9
|
LL | return String::new();
| ^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `String::new()`
#![warn(clippy::all)]
-#![allow(unused, clippy::println_empty_string)]
+#![allow(unused, clippy::println_empty_string, non_snake_case)]
#[derive(Clone, Debug)]
enum MaybeInst {
impl MaybeInst {
fn fill(&mut self) {
+ #[allow(non_fmt_panics)]
let filled = match *self {
- MaybeInst::Split1(goto1) => panic!(1),
- MaybeInst::Split2(goto2) => panic!(2),
+ MaybeInst::Split1(goto1) => panic!("1"),
+ MaybeInst::Split2(goto2) => panic!("2"),
_ => unimplemented!(),
};
unimplemented!()
}
fn issue3078() {
+ #[allow(clippy::single_match)]
match "a" {
stringify!(a) => {},
_ => {},
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:27:9
+ --> $DIR/non_expressive_names.rs:28:9
|
LL | let _1 = 1; //~ERROR Consider a more descriptive name
| ^^
= note: `-D clippy::just-underscores-and-digits` implied by `-D warnings`
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:28:9
+ --> $DIR/non_expressive_names.rs:29:9
|
LL | let ____1 = 1; //~ERROR Consider a more descriptive name
| ^^^^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:29:9
+ --> $DIR/non_expressive_names.rs:30:9
|
LL | let __1___2 = 12; //~ERROR Consider a more descriptive name
| ^^^^^^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:49:13
+ --> $DIR/non_expressive_names.rs:51:13
|
LL | let _1 = 1;
| ^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:50:13
+ --> $DIR/non_expressive_names.rs:52:13
|
LL | let ____1 = 1;
| ^^^^^
error: consider choosing a more descriptive name
- --> $DIR/non_expressive_names.rs:51:13
+ --> $DIR/non_expressive_names.rs:53:13
|
LL | let __1___2 = 12;
| ^^^^^^^
-// edition:2018
// run-rustfix
#![warn(clippy::option_if_let_else)]
#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)]
-// edition:2018
// run-rustfix
#![warn(clippy::option_if_let_else)]
#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)]
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:7:5
+ --> $DIR/option_if_let_else.rs:6:5
|
LL | / if let Some(x) = string {
LL | | (true, x)
= note: `-D clippy::option-if-let-else` implied by `-D warnings`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:25:13
+ --> $DIR/option_if_let_else.rs:24:13
|
LL | let _ = if let Some(s) = *string { s.len() } else { 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:26:13
+ --> $DIR/option_if_let_else.rs:25:13
|
LL | let _ = if let Some(s) = &num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:27:13
+ --> $DIR/option_if_let_else.rs:26:13
|
LL | let _ = if let Some(s) = &mut num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:33:13
+ --> $DIR/option_if_let_else.rs:32:13
|
LL | let _ = if let Some(ref s) = num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:34:13
+ --> $DIR/option_if_let_else.rs:33:13
|
LL | let _ = if let Some(mut s) = num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:40:13
+ --> $DIR/option_if_let_else.rs:39:13
|
LL | let _ = if let Some(ref mut s) = num {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:49:5
+ --> $DIR/option_if_let_else.rs:48:5
|
LL | / if let Some(x) = arg {
LL | | let y = x * x;
|
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:62:13
+ --> $DIR/option_if_let_else.rs:61:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
| |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:71:13
+ --> $DIR/option_if_let_else.rs:70:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:100:13
+ --> $DIR/option_if_let_else.rs:99:13
|
LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:109:13
+ --> $DIR/option_if_let_else.rs:108:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
|
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:137:13
+ --> $DIR/option_if_let_else.rs:136:13
|
LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or_else(|| s.len(), |x| s.len() + x)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:141:13
+ --> $DIR/option_if_let_else.rs:140:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
#![warn(clippy::panic_in_result_fn)]
#![allow(clippy::unnecessary_wraps)]
-
struct A;
impl A {
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:7:5
+ --> $DIR/panic_in_result_fn.rs:6:5
|
LL | / fn result_with_panic() -> Result<bool, String> // should emit lint
LL | | {
= note: `-D clippy::panic-in-result-fn` implied by `-D warnings`
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:9:9
+ --> $DIR/panic_in_result_fn.rs:8:9
|
LL | panic!("error");
| ^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:12:5
+ --> $DIR/panic_in_result_fn.rs:11:5
|
LL | / fn result_with_unimplemented() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:14:9
+ --> $DIR/panic_in_result_fn.rs:13:9
|
LL | unimplemented!();
| ^^^^^^^^^^^^^^^^
= note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:17:5
+ --> $DIR/panic_in_result_fn.rs:16:5
|
LL | / fn result_with_unreachable() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:19:9
+ --> $DIR/panic_in_result_fn.rs:18:9
|
LL | unreachable!();
| ^^^^^^^^^^^^^^
= note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:22:5
+ --> $DIR/panic_in_result_fn.rs:21:5
|
LL | / fn result_with_todo() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:24:9
+ --> $DIR/panic_in_result_fn.rs:23:9
|
LL | todo!("Finish this");
| ^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:53:1
+ --> $DIR/panic_in_result_fn.rs:52:1
|
LL | / fn function_result_with_panic() -> Result<bool, String> // should emit lint
LL | | {
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:55:5
+ --> $DIR/panic_in_result_fn.rs:54:5
|
LL | panic!("error");
| ^^^^^^^^^^^^^^^
- = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
- --> $DIR/panic_in_result_fn.rs:68:1
+ --> $DIR/panic_in_result_fn.rs:67:1
|
LL | / fn main() -> Result<(), String> {
LL | | todo!("finish main method");
|
= help: `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing
note: return Err() instead of panicking
- --> $DIR/panic_in_result_fn.rs:69:5
+ --> $DIR/panic_in_result_fn.rs:68:5
|
LL | todo!("finish main method");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-#![allow(
- unused,
- clippy::many_single_char_names,
- clippy::redundant_clone,
- clippy::if_then_panic
-)]
+#![allow(unused, clippy::many_single_char_names, clippy::redundant_clone)]
#![warn(clippy::ptr_arg)]
use std::borrow::Cow;
let _ = str.clone().clone();
}
}
+
+// No error for types behind an alias (#7699)
+type A = Vec<u8>;
+fn aliased(a: &A) {}
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
- --> $DIR/ptr_arg.rs:12:14
+ --> $DIR/ptr_arg.rs:7:14
|
LL | fn do_vec(x: &Vec<i64>) {
| ^^^^^^^^^ help: change this to: `&[i64]`
= note: `-D clippy::ptr-arg` implied by `-D warnings`
error: writing `&String` instead of `&str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:21:14
+ --> $DIR/ptr_arg.rs:16:14
|
LL | fn do_str(x: &String) {
| ^^^^^^^ help: change this to: `&str`
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:30:15
+ --> $DIR/ptr_arg.rs:25:15
|
LL | fn do_path(x: &PathBuf) {
| ^^^^^^^^ help: change this to: `&Path`
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
- --> $DIR/ptr_arg.rs:43:18
+ --> $DIR/ptr_arg.rs:38:18
|
LL | fn do_vec(x: &Vec<i64>);
| ^^^^^^^^^ help: change this to: `&[i64]`
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
- --> $DIR/ptr_arg.rs:56:14
+ --> $DIR/ptr_arg.rs:51:14
|
LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
| ^^^^^^^^
|
error: writing `&String` instead of `&str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:65:18
+ --> $DIR/ptr_arg.rs:60:18
|
LL | fn str_cloned(x: &String) -> String {
| ^^^^^^^
|
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:73:19
+ --> $DIR/ptr_arg.rs:68:19
|
LL | fn path_cloned(x: &PathBuf) -> PathBuf {
| ^^^^^^^^
|
error: writing `&String` instead of `&str` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:81:44
+ --> $DIR/ptr_arg.rs:76:44
|
LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
| ^^^^^^^
| ~
error: using a reference to `Cow` is not recommended
- --> $DIR/ptr_arg.rs:95:25
+ --> $DIR/ptr_arg.rs:90:25
|
LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
| ^^^^^^^^^^^ help: change this to: `&[i32]`
error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
- --> $DIR/ptr_arg.rs:148:21
+ --> $DIR/ptr_arg.rs:143:21
|
LL | fn foo_vec(vec: &Vec<u8>) {
| ^^^^^^^^
| ~~~~~~~~~~~~~~
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:153:23
+ --> $DIR/ptr_arg.rs:148:23
|
LL | fn foo_path(path: &PathBuf) {
| ^^^^^^^^
| ~~~~~~~~~~~~~~~~~~
error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
- --> $DIR/ptr_arg.rs:158:21
+ --> $DIR/ptr_arg.rs:153:21
|
LL | fn foo_str(str: &PathBuf) {
| ^^^^^^^^
Some(0)
}
-fn result_func(x: Result<i32, &str>) -> Result<i32, &str> {
+fn func_returning_result() -> Result<i32, i32> {
+ Ok(1)
+}
+
+fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
let _ = x?;
x?;
let y = if let Ok(x) = x {
x
} else {
- return Err("some error");
+ return Err(0);
+ };
+
+ // issue #7859
+ // no warning
+ let _ = if let Ok(x) = func_returning_result() {
+ x
+ } else {
+ return Err(0);
};
+ // no warning
+ if func_returning_result().is_err() {
+ return func_returning_result();
+ }
+
Ok(y)
}
Some(0)
}
-fn result_func(x: Result<i32, &str>) -> Result<i32, &str> {
+fn func_returning_result() -> Result<i32, i32> {
+ Ok(1)
+}
+
+fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
let _ = if let Ok(x) = x { x } else { return x };
if x.is_err() {
let y = if let Ok(x) = x {
x
} else {
- return Err("some error");
+ return Err(0);
+ };
+
+ // issue #7859
+ // no warning
+ let _ = if let Ok(x) = func_returning_result() {
+ x
+ } else {
+ return Err(0);
};
+ // no warning
+ if func_returning_result().is_err() {
+ return func_returning_result();
+ }
+
Ok(y)
}
| |_____^ help: replace it with: `f()?;`
error: this if-let-else may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:138:13
+ --> $DIR/question_mark.rs:142:13
|
LL | let _ = if let Ok(x) = x { x } else { return x };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?`
error: this block may be rewritten with the `?` operator
- --> $DIR/question_mark.rs:140:5
+ --> $DIR/question_mark.rs:144:5
|
LL | / if x.is_err() {
LL | | return x;
fn foo<F: Fn()>(_: &Alpha, _: F) {}
let x = Alpha;
// ok, data is moved while the clone is in use.
- foo(&x.clone(), move || {
+ foo(&x, move || {
let _ = x;
});
LL | let y = x.clone().join("matthias");
| ^^^^^^^^^
-error: aborting due to 14 previous errors
+error: redundant clone
+ --> $DIR/redundant_clone.rs:199:11
+ |
+LL | foo(&x.clone(), move || {
+ | ^^^^^^^^ help: remove this
+ |
+note: this value is dropped without further use
+ --> $DIR/redundant_clone.rs:199:10
+ |
+LL | foo(&x.clone(), move || {
+ | ^
+
+error: aborting due to 15 previous errors
#[allow(clippy::needless_return)]
(|| return 2)();
(|| -> Option<i32> { None? })();
+ #[allow(clippy::try_err)]
(|| -> Result<i32, i32> { Err(2)? })();
}
#![warn(clippy::redundant_else)]
-#![allow(clippy::needless_return)]
+#![allow(clippy::needless_return, clippy::if_same_then_else)]
fn main() {
loop {
1
};
// assign
- let a;
+ let mut a;
a = if foo() {
return;
} else {
-// edition:2018
// FIXME: run-rustfix waiting on multi-span suggestions
#![warn(clippy::ref_binding_to_reference)]
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:31:14
+ --> $DIR/ref_binding_to_reference.rs:30:14
|
LL | Some(ref x) => x,
| ^^^^^
| ~ ~~
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:37:14
+ --> $DIR/ref_binding_to_reference.rs:36:14
|
LL | Some(ref x) => {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:47:14
+ --> $DIR/ref_binding_to_reference.rs:46:14
|
LL | Some(ref x) => m2!(x),
| ^^^^^
| ~ ~~
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:52:15
+ --> $DIR/ref_binding_to_reference.rs:51:15
|
LL | let _ = |&ref x: &&String| {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:58:12
+ --> $DIR/ref_binding_to_reference.rs:57:12
|
LL | fn f2<'a>(&ref x: &&'a String) -> &'a String {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:65:11
+ --> $DIR/ref_binding_to_reference.rs:64:11
|
LL | fn f(&ref x: &&String) {
| ^^^^^
|
error: this pattern creates a reference to a reference
- --> $DIR/ref_binding_to_reference.rs:73:11
+ --> $DIR/ref_binding_to_reference.rs:72:11
|
LL | fn f(&ref x: &&String) {
| ^^^^^
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::new_without_default)]
#![allow(clippy::redundant_static_lifetimes)]
+#![allow(clippy::bind_instead_of_map)]
+#![allow(clippy::box_collection)]
+#![allow(clippy::blocks_in_if_conditions)]
+#![allow(clippy::map_unwrap_or)]
+#![allow(clippy::unwrap_used)]
+#![allow(clippy::expect_used)]
+#![allow(clippy::for_loops_over_fallibles)]
+#![allow(clippy::useless_conversion)]
+#![allow(clippy::invisible_characters)]
+#![allow(clippy::single_char_add_str)]
+#![allow(clippy::match_result_ok)]
+// uplifted lints
+#![allow(invalid_value)]
+#![allow(array_into_iter)]
+#![allow(unused_labels)]
+#![allow(drop_bounds)]
+#![allow(temporary_cstring_as_ptr)]
+#![allow(non_fmt_panics)]
+#![allow(unknown_lints)]
+#![allow(invalid_atomic_ordering)]
+#![allow(enum_intrinsics_non_enums)]
// warn for the old lint name here, to test if the renaming worked
+#![warn(clippy::module_name_repetitions)]
+#![warn(clippy::new_without_default)]
+#![warn(clippy::redundant_static_lifetimes)]
#![warn(clippy::cognitive_complexity)]
+#![warn(clippy::bind_instead_of_map)]
+#![warn(clippy::box_collection)]
+#![warn(clippy::blocks_in_if_conditions)]
+#![warn(clippy::blocks_in_if_conditions)]
+#![warn(clippy::map_unwrap_or)]
+#![warn(clippy::map_unwrap_or)]
+#![warn(clippy::map_unwrap_or)]
+#![warn(clippy::unwrap_used)]
+#![warn(clippy::unwrap_used)]
+#![warn(clippy::expect_used)]
+#![warn(clippy::expect_used)]
+#![warn(clippy::for_loops_over_fallibles)]
+#![warn(clippy::for_loops_over_fallibles)]
+#![warn(clippy::useless_conversion)]
+#![warn(clippy::invisible_characters)]
+#![warn(clippy::single_char_add_str)]
+#![warn(clippy::match_result_ok)]
+// uplifted lints
+#![warn(invalid_value)]
+#![warn(array_into_iter)]
+#![warn(unused_labels)]
+#![warn(drop_bounds)]
+#![warn(temporary_cstring_as_ptr)]
+#![warn(non_fmt_panics)]
+#![warn(unknown_lints)]
+#![warn(invalid_atomic_ordering)]
#![warn(enum_intrinsics_non_enums)]
-#[warn(clippy::module_name_repetitions)]
fn main() {}
-
-#[warn(clippy::new_without_default)]
-struct Foo;
-
-#[warn(clippy::redundant_static_lifetimes)]
-fn foo() {}
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::new_without_default)]
#![allow(clippy::redundant_static_lifetimes)]
+#![allow(clippy::bind_instead_of_map)]
+#![allow(clippy::box_collection)]
+#![allow(clippy::blocks_in_if_conditions)]
+#![allow(clippy::map_unwrap_or)]
+#![allow(clippy::unwrap_used)]
+#![allow(clippy::expect_used)]
+#![allow(clippy::for_loops_over_fallibles)]
+#![allow(clippy::useless_conversion)]
+#![allow(clippy::invisible_characters)]
+#![allow(clippy::single_char_add_str)]
+#![allow(clippy::match_result_ok)]
+// uplifted lints
+#![allow(invalid_value)]
+#![allow(array_into_iter)]
+#![allow(unused_labels)]
+#![allow(drop_bounds)]
+#![allow(temporary_cstring_as_ptr)]
+#![allow(non_fmt_panics)]
+#![allow(unknown_lints)]
+#![allow(invalid_atomic_ordering)]
+#![allow(enum_intrinsics_non_enums)]
// warn for the old lint name here, to test if the renaming worked
+#![warn(clippy::stutter)]
+#![warn(clippy::new_without_default_derive)]
+#![warn(clippy::const_static_lifetime)]
#![warn(clippy::cyclomatic_complexity)]
+#![warn(clippy::option_and_then_some)]
+#![warn(clippy::box_vec)]
+#![warn(clippy::block_in_if_condition_expr)]
+#![warn(clippy::block_in_if_condition_stmt)]
+#![warn(clippy::option_map_unwrap_or)]
+#![warn(clippy::option_map_unwrap_or_else)]
+#![warn(clippy::result_map_unwrap_or_else)]
+#![warn(clippy::option_unwrap_used)]
+#![warn(clippy::result_unwrap_used)]
+#![warn(clippy::option_expect_used)]
+#![warn(clippy::result_expect_used)]
+#![warn(clippy::for_loop_over_option)]
+#![warn(clippy::for_loop_over_result)]
+#![warn(clippy::identity_conversion)]
+#![warn(clippy::zero_width_space)]
+#![warn(clippy::single_char_push_str)]
+#![warn(clippy::if_let_some_result)]
+// uplifted lints
+#![warn(clippy::invalid_ref)]
+#![warn(clippy::into_iter_on_array)]
+#![warn(clippy::unused_label)]
+#![warn(clippy::drop_bounds)]
+#![warn(clippy::temporary_cstring_as_ptr)]
+#![warn(clippy::panic_params)]
+#![warn(clippy::unknown_clippy_lints)]
+#![warn(clippy::invalid_atomic_ordering)]
#![warn(clippy::mem_discriminant_non_enum)]
-#[warn(clippy::stutter)]
fn main() {}
-
-#[warn(clippy::new_without_default_derive)]
-struct Foo;
-
-#[warn(clippy::const_static_lifetime)]
-fn foo() {}
+error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
+ --> $DIR/rename.rs:31:9
+ |
+LL | #![warn(clippy::stutter)]
+ | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
+ |
+ = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
+error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
+ --> $DIR/rename.rs:32:9
+ |
+LL | #![warn(clippy::new_without_default_derive)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
+
+error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
+ --> $DIR/rename.rs:33:9
+ |
+LL | #![warn(clippy::const_static_lifetime)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
+
error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
- --> $DIR/rename.rs:10:9
+ --> $DIR/rename.rs:34:9
|
LL | #![warn(clippy::cyclomatic_complexity)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
+
+error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
+ --> $DIR/rename.rs:35:9
|
- = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+LL | #![warn(clippy::option_and_then_some)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
-error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
- --> $DIR/rename.rs:11:9
+error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
+ --> $DIR/rename.rs:36:9
|
-LL | #![warn(clippy::mem_discriminant_non_enum)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
+LL | #![warn(clippy::box_vec)]
+ | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
-error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
- --> $DIR/rename.rs:13:8
+error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
+ --> $DIR/rename.rs:37:9
|
-LL | #[warn(clippy::stutter)]
- | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
+LL | #![warn(clippy::block_in_if_condition_expr)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
-error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
- --> $DIR/rename.rs:16:8
+error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
+ --> $DIR/rename.rs:38:9
|
-LL | #[warn(clippy::new_without_default_derive)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
+LL | #![warn(clippy::block_in_if_condition_stmt)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
-error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
- --> $DIR/rename.rs:19:8
+error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
+ --> $DIR/rename.rs:39:9
+ |
+LL | #![warn(clippy::option_map_unwrap_or)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+
+error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+ --> $DIR/rename.rs:40:9
+ |
+LL | #![warn(clippy::option_map_unwrap_or_else)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+
+error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
+ --> $DIR/rename.rs:41:9
+ |
+LL | #![warn(clippy::result_map_unwrap_or_else)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
+
+error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
+ --> $DIR/rename.rs:42:9
+ |
+LL | #![warn(clippy::option_unwrap_used)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+
+error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
+ --> $DIR/rename.rs:43:9
+ |
+LL | #![warn(clippy::result_unwrap_used)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
+
+error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
+ --> $DIR/rename.rs:44:9
+ |
+LL | #![warn(clippy::option_expect_used)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
+
+error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
+ --> $DIR/rename.rs:45:9
+ |
+LL | #![warn(clippy::result_expect_used)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
+
+error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
+ --> $DIR/rename.rs:46:9
+ |
+LL | #![warn(clippy::for_loop_over_option)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+
+error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
+ --> $DIR/rename.rs:47:9
+ |
+LL | #![warn(clippy::for_loop_over_result)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
+
+error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
+ --> $DIR/rename.rs:48:9
+ |
+LL | #![warn(clippy::identity_conversion)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
+
+error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
+ --> $DIR/rename.rs:49:9
+ |
+LL | #![warn(clippy::zero_width_space)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
+
+error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
+ --> $DIR/rename.rs:50:9
+ |
+LL | #![warn(clippy::single_char_push_str)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
+
+error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
+ --> $DIR/rename.rs:51:9
+ |
+LL | #![warn(clippy::if_let_some_result)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
+
+error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
+ --> $DIR/rename.rs:53:9
+ |
+LL | #![warn(clippy::invalid_ref)]
+ | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
+
+error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
+ --> $DIR/rename.rs:54:9
+ |
+LL | #![warn(clippy::into_iter_on_array)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
+
+error: lint `clippy::unused_label` has been renamed to `unused_labels`
+ --> $DIR/rename.rs:55:9
+ |
+LL | #![warn(clippy::unused_label)]
+ | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
+
+error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
+ --> $DIR/rename.rs:56:9
+ |
+LL | #![warn(clippy::drop_bounds)]
+ | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
+
+error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
+ --> $DIR/rename.rs:57:9
+ |
+LL | #![warn(clippy::temporary_cstring_as_ptr)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
+
+error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
+ --> $DIR/rename.rs:58:9
+ |
+LL | #![warn(clippy::panic_params)]
+ | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
+
+error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
+ --> $DIR/rename.rs:59:9
+ |
+LL | #![warn(clippy::unknown_clippy_lints)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
+
+error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
+ --> $DIR/rename.rs:60:9
+ |
+LL | #![warn(clippy::invalid_atomic_ordering)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
+
+error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
+ --> $DIR/rename.rs:61:9
|
-LL | #[warn(clippy::const_static_lifetime)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
+LL | #![warn(clippy::mem_discriminant_non_enum)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
-error: aborting due to 5 previous errors
+error: aborting due to 30 previous errors
-// edition:2018
-
#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::missing_errors_doc,
-// edition:2018
-
#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::missing_errors_doc,
error: method `add` can be confused for the standard trait method `std::ops::Add::add`
- --> $DIR/method_list_1.rs:26:5
+ --> $DIR/method_list_1.rs:24:5
|
LL | / pub fn add(self, other: T) -> T {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Add` or choosing a less ambiguous method name
error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
- --> $DIR/method_list_1.rs:30:5
+ --> $DIR/method_list_1.rs:28:5
|
LL | / pub fn as_mut(&mut self) -> &mut T {
LL | | unimplemented!()
= help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
- --> $DIR/method_list_1.rs:34:5
+ --> $DIR/method_list_1.rs:32:5
|
LL | / pub fn as_ref(&self) -> &T {
LL | | unimplemented!()
= help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
- --> $DIR/method_list_1.rs:38:5
+ --> $DIR/method_list_1.rs:36:5
|
LL | / pub fn bitand(self, rhs: T) -> T {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
- --> $DIR/method_list_1.rs:42:5
+ --> $DIR/method_list_1.rs:40:5
|
LL | / pub fn bitor(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
- --> $DIR/method_list_1.rs:46:5
+ --> $DIR/method_list_1.rs:44:5
|
LL | / pub fn bitxor(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
- --> $DIR/method_list_1.rs:50:5
+ --> $DIR/method_list_1.rs:48:5
|
LL | / pub fn borrow(&self) -> &str {
LL | | unimplemented!()
= help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
- --> $DIR/method_list_1.rs:54:5
+ --> $DIR/method_list_1.rs:52:5
|
LL | / pub fn borrow_mut(&mut self) -> &mut str {
LL | | unimplemented!()
= help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
- --> $DIR/method_list_1.rs:58:5
+ --> $DIR/method_list_1.rs:56:5
|
LL | / pub fn clone(&self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
- --> $DIR/method_list_1.rs:62:5
+ --> $DIR/method_list_1.rs:60:5
|
LL | / pub fn cmp(&self, other: &Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
- --> $DIR/method_list_1.rs:70:5
+ --> $DIR/method_list_1.rs:68:5
|
LL | / pub fn deref(&self) -> &Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
- --> $DIR/method_list_1.rs:74:5
+ --> $DIR/method_list_1.rs:72:5
|
LL | / pub fn deref_mut(&mut self) -> &mut Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
error: method `div` can be confused for the standard trait method `std::ops::Div::div`
- --> $DIR/method_list_1.rs:78:5
+ --> $DIR/method_list_1.rs:76:5
|
LL | / pub fn div(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
- --> $DIR/method_list_1.rs:82:5
+ --> $DIR/method_list_1.rs:80:5
|
LL | / pub fn drop(&mut self) {
LL | | unimplemented!()
-// edition:2018
-
#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::missing_errors_doc,
error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
- --> $DIR/method_list_2.rs:27:5
+ --> $DIR/method_list_2.rs:25:5
|
LL | / pub fn eq(&self, other: &Self) -> bool {
LL | | unimplemented!()
= help: consider implementing the trait `std::cmp::PartialEq` or choosing a less ambiguous method name
error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
- --> $DIR/method_list_2.rs:31:5
+ --> $DIR/method_list_2.rs:29:5
|
LL | / pub fn from_iter<T>(iter: T) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name
error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
- --> $DIR/method_list_2.rs:35:5
+ --> $DIR/method_list_2.rs:33:5
|
LL | / pub fn from_str(s: &str) -> Result<Self, Self> {
LL | | unimplemented!()
= help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
- --> $DIR/method_list_2.rs:39:5
+ --> $DIR/method_list_2.rs:37:5
|
LL | / pub fn hash(&self, state: &mut T) {
LL | | unimplemented!()
= help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
error: method `index` can be confused for the standard trait method `std::ops::Index::index`
- --> $DIR/method_list_2.rs:43:5
+ --> $DIR/method_list_2.rs:41:5
|
LL | / pub fn index(&self, index: usize) -> &Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
- --> $DIR/method_list_2.rs:47:5
+ --> $DIR/method_list_2.rs:45:5
|
LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
- --> $DIR/method_list_2.rs:51:5
+ --> $DIR/method_list_2.rs:49:5
|
LL | / pub fn into_iter(self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
- --> $DIR/method_list_2.rs:55:5
+ --> $DIR/method_list_2.rs:53:5
|
LL | / pub fn mul(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
- --> $DIR/method_list_2.rs:59:5
+ --> $DIR/method_list_2.rs:57:5
|
LL | / pub fn neg(self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
- --> $DIR/method_list_2.rs:63:5
+ --> $DIR/method_list_2.rs:61:5
|
LL | / pub fn next(&mut self) -> Option<Self> {
LL | | unimplemented!()
= help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
error: method `not` can be confused for the standard trait method `std::ops::Not::not`
- --> $DIR/method_list_2.rs:67:5
+ --> $DIR/method_list_2.rs:65:5
|
LL | / pub fn not(self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
- --> $DIR/method_list_2.rs:71:5
+ --> $DIR/method_list_2.rs:69:5
|
LL | / pub fn rem(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
- --> $DIR/method_list_2.rs:75:5
+ --> $DIR/method_list_2.rs:73:5
|
LL | / pub fn shl(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
- --> $DIR/method_list_2.rs:79:5
+ --> $DIR/method_list_2.rs:77:5
|
LL | / pub fn shr(self, rhs: Self) -> Self {
LL | | unimplemented!()
= help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
- --> $DIR/method_list_2.rs:83:5
+ --> $DIR/method_list_2.rs:81:5
|
LL | / pub fn sub(self, rhs: Self) -> Self {
LL | | unimplemented!()
#![warn(clippy::similar_names)]
-#![allow(unused, clippy::println_empty_string)]
+#![allow(
+ unused,
+ clippy::println_empty_string,
+ clippy::empty_loop,
+ clippy::diverging_sub_expression
+)]
struct Foo {
apple: i32,
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:15:9
+ --> $DIR/similar_names.rs:20:9
|
LL | let bpple: i32;
| ^^^^^
|
= note: `-D clippy::similar-names` implied by `-D warnings`
note: existing binding defined here
- --> $DIR/similar_names.rs:13:9
+ --> $DIR/similar_names.rs:18:9
|
LL | let apple: i32;
| ^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:17:9
+ --> $DIR/similar_names.rs:22:9
|
LL | let cpple: i32;
| ^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:13:9
+ --> $DIR/similar_names.rs:18:9
|
LL | let apple: i32;
| ^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:41:9
+ --> $DIR/similar_names.rs:46:9
|
LL | let bluby: i32;
| ^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:40:9
+ --> $DIR/similar_names.rs:45:9
|
LL | let blubx: i32;
| ^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:45:9
+ --> $DIR/similar_names.rs:50:9
|
LL | let coke: i32;
| ^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:43:9
+ --> $DIR/similar_names.rs:48:9
|
LL | let cake: i32;
| ^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:63:9
+ --> $DIR/similar_names.rs:68:9
|
LL | let xyzeabc: i32;
| ^^^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:61:9
+ --> $DIR/similar_names.rs:66:9
|
LL | let xyz1abc: i32;
| ^^^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:67:9
+ --> $DIR/similar_names.rs:72:9
|
LL | let parsee: i32;
| ^^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:65:9
+ --> $DIR/similar_names.rs:70:9
|
LL | let parser: i32;
| ^^^^^^
error: binding's name is too similar to existing binding
- --> $DIR/similar_names.rs:88:16
+ --> $DIR/similar_names.rs:93:16
|
LL | bpple: sprang,
| ^^^^^^
|
note: existing binding defined here
- --> $DIR/similar_names.rs:87:16
+ --> $DIR/similar_names.rs:92:16
|
LL | apple: spring,
| ^^^^^^
// run-rustfix
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
// run-rustfix
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
error: this import is redundant
- --> $DIR/single_component_path_imports.rs:24:5
+ --> $DIR/single_component_path_imports.rs:23:5
|
LL | use regex;
| ^^^^^^^^^^ help: remove it entirely
= note: `-D clippy::single-component-path-imports` implied by `-D warnings`
error: this import is redundant
- --> $DIR/single_component_path_imports.rs:6:1
+ --> $DIR/single_component_path_imports.rs:5:1
|
LL | use regex;
| ^^^^^^^^^^ help: remove it entirely
// run-rustfix
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
// run-rustfix
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
error: this import is redundant
- --> $DIR/single_component_path_imports_macro.rs:16:1
+ --> $DIR/single_component_path_imports_macro.rs:15:1
|
LL | use m2; // fail
| ^^^^^^^ help: remove it entirely
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
error: this import is redundant
- --> $DIR/single_component_path_imports_nested_first.rs:14:10
+ --> $DIR/single_component_path_imports_nested_first.rs:13:10
|
LL | use {regex, serde};
| ^^^^^
= help: remove this import
error: this import is redundant
- --> $DIR/single_component_path_imports_nested_first.rs:14:17
+ --> $DIR/single_component_path_imports_nested_first.rs:13:17
|
LL | use {regex, serde};
| ^^^^^
= help: remove this import
error: this import is redundant
- --> $DIR/single_component_path_imports_nested_first.rs:5:1
+ --> $DIR/single_component_path_imports_nested_first.rs:4:1
|
LL | use regex;
| ^^^^^^^^^^ help: remove it entirely
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
-// edition:2018
#![warn(clippy::single_component_path_imports)]
#![allow(unused_imports)]
--- /dev/null
+#[warn(clippy::string_slice)]
+#[allow(clippy::no_effect)]
+
+fn main() {
+ &"Ölkanne"[1..];
+ let m = "Mötörhead";
+ &m[2..5];
+ let s = String::from(m);
+ &s[0..2];
+}
--- /dev/null
+error: indexing into a string may panic if the index is within a UTF-8 character
+ --> $DIR/string_slice.rs:5:6
+ |
+LL | &"Ölkanne"[1..];
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::string-slice` implied by `-D warnings`
+
+error: indexing into a string may panic if the index is within a UTF-8 character
+ --> $DIR/string_slice.rs:7:6
+ |
+LL | &m[2..5];
+ | ^^^^^^^
+
+error: indexing into a string may panic if the index is within a UTF-8 character
+ --> $DIR/string_slice.rs:9:6
+ |
+LL | &s[0..2];
+ | ^^^^^^^
+
+error: aborting due to 3 previous errors
+
// aux-build:proc_macro_suspicious_else_formatting.rs
#![warn(clippy::suspicious_else_formatting)]
+#![allow(clippy::if_same_then_else)]
extern crate proc_macro_suspicious_else_formatting;
use proc_macro_suspicious_else_formatting::DeriveBadSpan;
error: this looks like an `else {..}` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:16:6
+ --> $DIR/suspicious_else_formatting.rs:17:6
|
LL | } {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the next block
error: this looks like an `else if` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:20:6
+ --> $DIR/suspicious_else_formatting.rs:21:6
|
LL | } if foo() {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
error: this looks like an `else if` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:27:10
+ --> $DIR/suspicious_else_formatting.rs:28:10
|
LL | } if foo() {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
error: this looks like an `else if` but the `else` is missing
- --> $DIR/suspicious_else_formatting.rs:35:10
+ --> $DIR/suspicious_else_formatting.rs:36:10
|
LL | } if foo() {
| ^
= note: to remove this lint, add the missing `else` or add a new line before the second `if`
error: this is an `else {..}` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:44:6
+ --> $DIR/suspicious_else_formatting.rs:45:6
|
LL | } else
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
error: this is an `else if` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:56:6
+ --> $DIR/suspicious_else_formatting.rs:57:6
|
LL | } else
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
error: this is an `else if` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:61:6
+ --> $DIR/suspicious_else_formatting.rs:62:6
|
LL | }
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `if`
error: this is an `else {..}` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:88:6
+ --> $DIR/suspicious_else_formatting.rs:89:6
|
LL | }
| ______^
= note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}`
error: this is an `else {..}` but the formatting might hide it
- --> $DIR/suspicious_else_formatting.rs:96:6
+ --> $DIR/suspicious_else_formatting.rs:97:6
|
LL | }
| ______^
#![warn(clippy::suspicious_operation_groupings)]
+#![allow(clippy::eq_op)]
struct Vec3 {
x: f64,
}
}
-fn inside_an_if_statement(s1: &S, s2: &S) {
+fn inside_an_if_statement(s1: &mut S, s2: &S) {
// There's no `s1.b`
if s1.a < s2.a && s1.a < s2.b {
s1.c = s2.c;
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:14:9
+ --> $DIR/suspicious_operation_groupings.rs:15:9
|
LL | self.x == other.y && self.y == other.y && self.z == other.z
| ^^^^^^^^^^^^^^^^^ help: did you mean: `self.x == other.x`
= note: `-D clippy::suspicious-operation-groupings` implied by `-D warnings`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:27:20
+ --> $DIR/suspicious_operation_groupings.rs:28:20
|
LL | s1.a < s2.a && s1.a < s2.b
| ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:75:33
+ --> $DIR/suspicious_operation_groupings.rs:76:33
|
LL | s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:80:19
+ --> $DIR/suspicious_operation_groupings.rs:81:19
|
LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:80:19
+ --> $DIR/suspicious_operation_groupings.rs:81:19
|
LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:85:19
+ --> $DIR/suspicious_operation_groupings.rs:86:19
|
LL | s1.a * s2.a + s2.b * s2.b + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:90:19
+ --> $DIR/suspicious_operation_groupings.rs:91:19
|
LL | s1.a * s2.a + s1.b * s1.b + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:95:5
+ --> $DIR/suspicious_operation_groupings.rs:96:5
|
LL | s1.a * s1.a + s1.b * s2.b + s1.c * s2.c
| ^^^^^^^^^^^ help: did you mean: `s1.a * s2.a`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:100:33
+ --> $DIR/suspicious_operation_groupings.rs:101:33
|
LL | s1.a * s2.a + s1.b * s2.b + s1.c * s1.c
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:113:20
+ --> $DIR/suspicious_operation_groupings.rs:114:20
|
LL | (s1.a * s2.a + s1.b * s1.b)
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:118:34
+ --> $DIR/suspicious_operation_groupings.rs:119:34
|
LL | (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d)
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:123:38
+ --> $DIR/suspicious_operation_groupings.rs:124:38
|
LL | (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:128:39
+ --> $DIR/suspicious_operation_groupings.rs:129:39
|
LL | ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:133:42
+ --> $DIR/suspicious_operation_groupings.rs:134:42
|
LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d)))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:133:42
+ --> $DIR/suspicious_operation_groupings.rs:134:42
|
LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d)))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:138:40
+ --> $DIR/suspicious_operation_groupings.rs:139:40
|
LL | (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:143:40
+ --> $DIR/suspicious_operation_groupings.rs:144:40
|
LL | ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)))
| ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:148:20
+ --> $DIR/suspicious_operation_groupings.rs:149:20
|
LL | (s1.a * s2.a + s2.b * s2.b) / 2
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:153:35
+ --> $DIR/suspicious_operation_groupings.rs:154:35
|
LL | i32::swap_bytes(s1.a * s2.a + s2.b * s2.b)
| ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:158:29
+ --> $DIR/suspicious_operation_groupings.rs:159:29
|
LL | s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d
| ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:163:17
+ --> $DIR/suspicious_operation_groupings.rs:164:17
|
LL | s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d
| ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:172:77
+ --> $DIR/suspicious_operation_groupings.rs:173:77
|
LL | (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `(n1.inner.2).0 == (n2.inner.2).0`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:186:25
+ --> $DIR/suspicious_operation_groupings.rs:187:25
|
LL | s1.a <= s2.a && s1.a <= s2.b
| ^^^^^^^^^^^^ help: did you mean: `s1.b <= s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:192:23
+ --> $DIR/suspicious_operation_groupings.rs:193:23
|
LL | if s1.a < s2.a && s1.a < s2.b {
| ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:199:48
+ --> $DIR/suspicious_operation_groupings.rs:200:48
|
LL | -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d)))
| ^^^^^^^^^^^^^ help: did you mean: `-s1.c * -s2.c`
error: this sequence of operators looks suspiciously like a bug
- --> $DIR/suspicious_operation_groupings.rs:204:27
+ --> $DIR/suspicious_operation_groupings.rs:205:27
|
LL | -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a })
| ^^^^^^^^^^^^^ help: did you mean: `-s1.b < -s2.b`
--- /dev/null
+#![warn(clippy::unit_hash)]
+
+use std::collections::hash_map::DefaultHasher;
+use std::hash::Hash;
+
+enum Foo {
+ Empty,
+ WithValue(u8),
+}
+
+fn do_nothing() {}
+
+fn main() {
+ let mut state = DefaultHasher::new();
+ let my_enum = Foo::Empty;
+
+ match my_enum {
+ Foo::Empty => ().hash(&mut state),
+ Foo::WithValue(x) => x.hash(&mut state),
+ }
+
+ let res = ();
+ res.hash(&mut state);
+
+ #[allow(clippy::unit_arg)]
+ do_nothing().hash(&mut state);
+}
--- /dev/null
+error: this call to `hash` on the unit type will do nothing
+ --> $DIR/unit_hash.rs:18:23
+ |
+LL | Foo::Empty => ().hash(&mut state),
+ | ^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
+ |
+ = note: `-D clippy::unit-hash` implied by `-D warnings`
+ = note: the implementation of `Hash` for `()` is a no-op
+
+error: this call to `hash` on the unit type will do nothing
+ --> $DIR/unit_hash.rs:23:5
+ |
+LL | res.hash(&mut state);
+ | ^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
+ |
+ = note: the implementation of `Hash` for `()` is a no-op
+
+error: this call to `hash` on the unit type will do nothing
+ --> $DIR/unit_hash.rs:26:5
+ |
+LL | do_nothing().hash(&mut state);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)`
+ |
+ = note: the implementation of `Hash` for `()` is a no-op
+
+error: aborting due to 3 previous errors
+
-// edition:2018
#![warn(clippy::unused_async)]
async fn foo() -> i32 {
error: unused `async` for function with no await statements
- --> $DIR/unused_async.rs:4:1
+ --> $DIR/unused_async.rs:3:1
|
LL | / async fn foo() -> i32 {
LL | | 4
// run-rustfix
-// edition:2018
// aux-build:proc_macro_derive.rs
#![warn(clippy::use_self)]
// run-rustfix
-// edition:2018
// aux-build:proc_macro_derive.rs
#![warn(clippy::use_self)]
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:23:21
+ --> $DIR/use_self.rs:22:21
|
LL | fn new() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
= note: `-D clippy::use-self` implied by `-D warnings`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:24:13
+ --> $DIR/use_self.rs:23:13
|
LL | Foo {}
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:26:22
+ --> $DIR/use_self.rs:25:22
|
LL | fn test() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:27:13
+ --> $DIR/use_self.rs:26:13
|
LL | Foo::new()
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:32:25
+ --> $DIR/use_self.rs:31:25
|
LL | fn default() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:33:13
+ --> $DIR/use_self.rs:32:13
|
LL | Foo::new()
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:98:24
+ --> $DIR/use_self.rs:97:24
|
LL | fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:98:55
+ --> $DIR/use_self.rs:97:55
|
LL | fn bad(foos: &[Foo]) -> impl Iterator<Item = &Foo> {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:113:13
+ --> $DIR/use_self.rs:112:13
|
LL | TS(0)
| ^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:148:29
+ --> $DIR/use_self.rs:147:29
|
LL | fn bar() -> Bar {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:149:21
+ --> $DIR/use_self.rs:148:21
|
LL | Bar { foo: Foo {} }
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:160:21
+ --> $DIR/use_self.rs:159:21
|
LL | fn baz() -> Foo {
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:161:13
+ --> $DIR/use_self.rs:160:13
|
LL | Foo {}
| ^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:178:21
+ --> $DIR/use_self.rs:177:21
|
LL | let _ = Enum::B(42);
| ^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:179:21
+ --> $DIR/use_self.rs:178:21
|
LL | let _ = Enum::C { field: true };
| ^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:180:21
+ --> $DIR/use_self.rs:179:21
|
LL | let _ = Enum::A;
| ^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:222:13
+ --> $DIR/use_self.rs:221:13
|
LL | nested::A::fun_1();
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:223:13
+ --> $DIR/use_self.rs:222:13
|
LL | nested::A::A;
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:225:13
+ --> $DIR/use_self.rs:224:13
|
LL | nested::A {};
| ^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:244:13
+ --> $DIR/use_self.rs:243:13
|
LL | TestStruct::from_something()
| ^^^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:258:25
+ --> $DIR/use_self.rs:257:25
|
LL | async fn g() -> S {
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:259:13
+ --> $DIR/use_self.rs:258:13
|
LL | S {}
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:263:16
+ --> $DIR/use_self.rs:262:16
|
LL | &p[S::A..S::B]
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:263:22
+ --> $DIR/use_self.rs:262:22
|
LL | &p[S::A..S::B]
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:286:29
+ --> $DIR/use_self.rs:285:29
|
LL | fn foo(value: T) -> Foo<T> {
| ^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:287:13
+ --> $DIR/use_self.rs:286:13
|
LL | Foo::<T> { value }
| ^^^^^^^^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:459:13
+ --> $DIR/use_self.rs:458:13
|
LL | A::new::<submod::B>(submod::B {})
| ^ help: use the applicable keyword: `Self`
error: unnecessary structure name repetition
- --> $DIR/use_self.rs:496:13
+ --> $DIR/use_self.rs:495:13
|
LL | S2::new()
| ^^ help: use the applicable keyword: `Self`
-// edition:2018
// aux-build:proc_macro_derive.rs
#![feature(rustc_private)]
error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:26:5
+ --> $DIR/used_underscore_binding.rs:25:5
|
LL | _foo + 1
| ^^^^
= note: `-D clippy::used-underscore-binding` implied by `-D warnings`
error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:31:20
+ --> $DIR/used_underscore_binding.rs:30:20
|
LL | println!("{}", _foo);
| ^^^^
error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:32:16
+ --> $DIR/used_underscore_binding.rs:31:16
|
LL | assert_eq!(_foo, _foo);
| ^^^^
error: used binding `_foo` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:32:22
+ --> $DIR/used_underscore_binding.rs:31:22
|
LL | assert_eq!(_foo, _foo);
| ^^^^
error: used binding `_underscore_field` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:45:5
+ --> $DIR/used_underscore_binding.rs:44:5
|
LL | s._underscore_field += 1;
| ^^^^^^^^^^^^^^^^^^^
error: used binding `_i` which is prefixed with an underscore. A leading underscore signals that a binding will not be used
- --> $DIR/used_underscore_binding.rs:100:16
+ --> $DIR/used_underscore_binding.rs:99:16
|
LL | uses_i(_i);
| ^^
+// edition:2015
// run-rustfix
// aux-build:wildcard_imports_helper.rs
+// the 2015 edition here is needed because edition 2018 changed the module system
+// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
+// no longer detects some of the cases starting with Rust 2018.
+// FIXME: We should likely add another edition 2021 test case for this lint
+
#![warn(clippy::wildcard_imports)]
-//#![allow(clippy::redundant_pub_crate)]
#![allow(unused)]
#![allow(clippy::unnecessary_wraps)]
#![warn(unused_imports)]
+// edition:2015
// run-rustfix
// aux-build:wildcard_imports_helper.rs
+// the 2015 edition here is needed because edition 2018 changed the module system
+// (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint
+// no longer detects some of the cases starting with Rust 2018.
+// FIXME: We should likely add another edition 2021 test case for this lint
+
#![warn(clippy::wildcard_imports)]
-//#![allow(clippy::redundant_pub_crate)]
#![allow(unused)]
#![allow(clippy::unnecessary_wraps)]
#![warn(unused_imports)]
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:12:5
+ --> $DIR/wildcard_imports.rs:17:5
|
LL | use crate::fn_mod::*;
| ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
= note: `-D clippy::wildcard-imports` implied by `-D warnings`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:13:5
+ --> $DIR/wildcard_imports.rs:18:5
|
LL | use crate::mod_mod::*;
| ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:14:5
+ --> $DIR/wildcard_imports.rs:19:5
|
LL | use crate::multi_fn_mod::*;
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:16:5
+ --> $DIR/wildcard_imports.rs:21:5
|
LL | use crate::struct_mod::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:20:5
+ --> $DIR/wildcard_imports.rs:25:5
|
LL | use wildcard_imports_helper::inner::inner_for_self_import::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:21:5
+ --> $DIR/wildcard_imports.rs:26:5
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:92:13
+ --> $DIR/wildcard_imports.rs:97:13
|
LL | use crate::fn_mod::*;
| ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:98:75
+ --> $DIR/wildcard_imports.rs:103:75
|
LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
| ^ help: try: `inner_extern_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:99:13
+ --> $DIR/wildcard_imports.rs:104:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:110:20
+ --> $DIR/wildcard_imports.rs:115:20
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^ help: try: `inner::inner_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:110:30
+ --> $DIR/wildcard_imports.rs:115:30
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^^ help: try: `inner2::inner_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:117:13
+ --> $DIR/wildcard_imports.rs:122:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:146:9
+ --> $DIR/wildcard_imports.rs:151:9
|
LL | use crate::in_fn_test::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:155:9
+ --> $DIR/wildcard_imports.rs:160:9
|
LL | use crate:: in_fn_test:: * ;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:156:9
+ --> $DIR/wildcard_imports.rs:161:9
|
LL | use crate:: fn_mod::
| _________^
| |_________^ help: try: `crate:: fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:167:13
+ --> $DIR/wildcard_imports.rs:172:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:202:17
+ --> $DIR/wildcard_imports.rs:207:17
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::insidefoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:210:13
+ --> $DIR/wildcard_imports.rs:215:13
|
LL | use super_imports::*;
| ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:219:17
+ --> $DIR/wildcard_imports.rs:224:17
|
LL | use super::super::*;
| ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:228:13
+ --> $DIR/wildcard_imports.rs:233:13
|
LL | use super::super::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:236:13
+ --> $DIR/wildcard_imports.rs:241:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
-// edition:2018
#![warn(clippy::wrong_self_convention)]
#![allow(dead_code)]
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:17:17
+ --> $DIR/wrong_self_convention.rs:16:17
|
LL | fn from_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:23:21
+ --> $DIR/wrong_self_convention.rs:22:21
|
LL | pub fn from_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:35:15
+ --> $DIR/wrong_self_convention.rs:34:15
|
LL | fn as_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:37:17
+ --> $DIR/wrong_self_convention.rs:36:17
|
LL | fn into_i32(&self) {}
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:39:15
+ --> $DIR/wrong_self_convention.rs:38:15
|
LL | fn is_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
- --> $DIR/wrong_self_convention.rs:41:15
+ --> $DIR/wrong_self_convention.rs:40:15
|
LL | fn to_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:43:17
+ --> $DIR/wrong_self_convention.rs:42:17
|
LL | fn from_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:45:19
+ --> $DIR/wrong_self_convention.rs:44:19
|
LL | pub fn as_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:46:21
+ --> $DIR/wrong_self_convention.rs:45:21
|
LL | pub fn into_i64(&self) {}
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:47:19
+ --> $DIR/wrong_self_convention.rs:46:19
|
LL | pub fn is_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
- --> $DIR/wrong_self_convention.rs:48:19
+ --> $DIR/wrong_self_convention.rs:47:19
|
LL | pub fn to_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:49:21
+ --> $DIR/wrong_self_convention.rs:48:21
|
LL | pub fn from_i64(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:94:19
+ --> $DIR/wrong_self_convention.rs:93:19
|
LL | fn as_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:97:25
+ --> $DIR/wrong_self_convention.rs:96:25
|
LL | fn into_i32_ref(&self) {}
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:99:19
+ --> $DIR/wrong_self_convention.rs:98:19
|
LL | fn is_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:103:21
+ --> $DIR/wrong_self_convention.rs:102:21
|
LL | fn from_i32(self) {}
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
- --> $DIR/wrong_self_convention.rs:118:19
+ --> $DIR/wrong_self_convention.rs:117:19
|
LL | fn as_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:121:25
+ --> $DIR/wrong_self_convention.rs:120:25
|
LL | fn into_i32_ref(&self);
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `is_*` usually take `self` by reference or no `self`
- --> $DIR/wrong_self_convention.rs:123:19
+ --> $DIR/wrong_self_convention.rs:122:19
|
LL | fn is_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:127:21
+ --> $DIR/wrong_self_convention.rs:126:21
|
LL | fn from_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `into_*` usually take `self` by value
- --> $DIR/wrong_self_convention.rs:145:25
+ --> $DIR/wrong_self_convention.rs:144:25
|
LL | fn into_i32_ref(&self);
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention.rs:151:21
+ --> $DIR/wrong_self_convention.rs:150:21
|
LL | fn from_i32(self);
| ^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value
- --> $DIR/wrong_self_convention.rs:175:22
+ --> $DIR/wrong_self_convention.rs:174:22
|
LL | fn to_u64_v2(&self) -> u64 {
| ^^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
- --> $DIR/wrong_self_convention.rs:184:19
+ --> $DIR/wrong_self_convention.rs:183:19
|
LL | fn to_u64(self) -> u64 {
| ^^^^
-// edition:2018
#![warn(clippy::wrong_self_convention)]
#![allow(dead_code)]
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention2.rs:55:29
+ --> $DIR/wrong_self_convention2.rs:54:29
|
LL | pub fn from_be_self(self) -> Self {
| ^^^^
= help: consider choosing a less ambiguous name
error: methods called `from_*` usually take no `self`
- --> $DIR/wrong_self_convention2.rs:64:25
+ --> $DIR/wrong_self_convention2.rs:63:25
|
LL | fn from_be_self(self) -> Self;
| ^^^^
-// edition:2018
#![warn(clippy::wrong_self_convention)]
#![allow(dead_code)]
error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference
- --> $DIR/wrong_self_conventions_mut.rs:15:24
+ --> $DIR/wrong_self_conventions_mut.rs:14:24
|
LL | pub fn to_many(&mut self) -> Option<&mut [T]> {
| ^^^^^^^^^
= help: consider choosing a less ambiguous name
error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference
- --> $DIR/wrong_self_conventions_mut.rs:23:28
+ --> $DIR/wrong_self_conventions_mut.rs:22:28
|
LL | pub fn to_many_mut(&self) -> Option<&[T]> {
| ^^^^^
if let Some(edition) = config.parse_edition(ln) {
self.compile_flags.push(format!("--edition={}", edition));
has_edition = true;
- if edition == "2021" {
- self.compile_flags.push("-Zunstable-options".to_string());
- }
}
config.parse_and_update_revisions(ln, &mut self.revisions);
let mut config = config();
config.target = "x86_64-pc-windows-gnu".to_owned();
- assert!(check_ignore(&config, "// only-i686"));
+ assert!(check_ignore(&config, "// only-x86"));
assert!(check_ignore(&config, "// only-linux"));
assert!(check_ignore(&config, "// only-msvc"));
assert!(check_ignore(&config, "// only-32bit"));
get_lib_name(&aux_path.trim_end_matches(".rs").replace('-', "_"), is_dylib);
rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir.display(), lib_name));
}
- if !self.props.aux_crates.is_empty() {
- rustc.arg("-Zunstable-options");
- }
aux_dir
}
];
static ASM_SUPPORTED_ARCHS: &[&str] = &[
- "x86", "x86_64", "arm", "aarch64", "riscv32", "riscv64", "nvptx64", "hexagon", "mips",
- "mips64", "spirv", "wasm32",
+ "x86", "x86_64", "arm", "aarch64", "riscv32",
+ "riscv64",
+ // These targets require an additional asm_experimental_arch feature.
+ // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32",
];
pub fn has_asm_support(triple: &str) -> bool {
("core/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
("alloc/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
("std/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]),
+ ("core/primitive.str.html", &["begin</code>, <code>end"]),
+ ("std/primitive.str.html", &["begin</code>, <code>end"]),
];
-Subproject commit fa91a89193d26e6a86e2eee1cbaa38cb28ccebe1
+Subproject commit 9c18177cd36fe07a3c251234240a9c77a4e66785
-Subproject commit 91cbda43c2af82b9377eff70a21f59ade18cd23c
+Subproject commit 2c0f433fd2e838ae181f87019b6f1fefe33c6f54
"test_folder": "",
"test_file": "",
};
- var correspondances = {
+ var correspondences = {
"--resource-suffix": "resource_suffix",
"--doc-folder": "doc_folder",
"--test-folder": "test_folder",
};
for (var i = 0; i < args.length; ++i) {
- if (args[i] === "--resource-suffix"
- || args[i] === "--doc-folder"
- || args[i] === "--test-folder"
- || args[i] === "--test-file"
- || args[i] === "--crate-name") {
+ if (correspondences.hasOwnProperty(args[i])) {
i += 1;
if (i >= args.length) {
console.log("Missing argument after `" + args[i - 1] + "` option.");
return null;
}
- opts[correspondances[args[i - 1]]] = args[i];
+ opts[correspondences[args[i - 1]]] = args[i];
} else if (args[i] === "--help") {
showHelp();
process.exit(0);
--- /dev/null
+name: rustdoc check
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+
+jobs:
+ rustdoc_check:
+ runs-on: ubuntu-latest
+ name: rustdoc check
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+
+ - name: install rustup
+ run: |
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
+ sh rustup-init.sh -y --default-toolchain none
+ rustup target add x86_64-unknown-linux-gnu
+
+ - name: document rustfmt
+ env:
+ RUSTDOCFLAGS: --document-private-items --enable-index-page --show-type-layout --generate-link-to-definition -Zunstable-options -Dwarnings
+ run: cargo doc -Zskip-rustdoc-fingerprint --no-deps -p rustfmt-nightly -p rustfmt-config_proc_macro
Controls the strategy for how imports are grouped together.
- **Default value**: `Preserve`
-- **Possible values**: `Preserve`, `StdExternalCrate`
+- **Possible values**: `Preserve`, `StdExternalCrate`, `One`
- **Stable**: No
#### `Preserve` (default):
use crate::models::Event;
```
+#### `One`:
+
+Discard existing import groups, and create a single group for everything
+
+```rust
+use super::schema::{Context, Payload};
+use super::update::convert_publish_payload;
+use crate::models::Event;
+use alloc::alloc::Layout;
+use broker::database::PooledConnection;
+use chrono::Utc;
+use core::f32;
+use juniper::{FieldError, FieldResult};
+use std::sync::Arc;
+use uuid::Uuid;
+```
+
## `reorder_modules`
Reorder `mod` declarations alphabetically in group.
## Debugging
Some `rewrite_*` methods use the `debug!` macro for printing useful information.
-These messages can be printed by using the environment variable `RUST_LOG=rustfmt=DEBUG`.
+These messages can be printed by using the environment variable `RUSTFMT_LOG=rustfmt=DEBUG`.
These traces can be helpful in understanding which part of the code was used
and get a better grasp on the execution flow.
## Limitations
-Rustfmt tries to work on as much Rust code as possible, sometimes, the code
+Rustfmt tries to work on as much Rust code as possible. Sometimes, the code
doesn't even need to compile! As we approach a 1.0 release we are also looking
to limit areas of instability; in particular, post-1.0, the formatting of most
code should not change as Rustfmt improves. However, there are some things that
binary and library targets of your crate.
You can run `rustfmt --help` for information about available arguments.
+The easiest way to run rustfmt against a project is with `cargo fmt`. `cargo fmt` works on both
+single-crate projects and [cargo workspaces](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html).
+Please see `cargo fmt --help` for usage information.
+
+You can specify the path to your own `rustfmt` binary for cargo to use by setting the`RUSTFMT`
+environment variable. This was added in v1.4.22, so you must have this version or newer to leverage this feature (`cargo fmt --version`)
+
+### Running `rustfmt` directly
+
+To format individual files or arbitrary codes from stdin, the `rustfmt` binary should be used. Some
+examples follow:
+
+- `rustfmt lib.rs main.rs` will format "lib.rs" and "main.rs" in place
+- `rustfmt` will read a code from stdin and write formatting to stdout
+ - `echo "fn main() {}" | rustfmt` would emit "fn main() {}".
+
+For more information, including arguments and emit options, see `rustfmt --help`.
+
+### Verifying code is formatted
When running with `--check`, Rustfmt will exit with `0` if Rustfmt would not
make any formatting changes to the input, and `1` if Rustfmt would make changes.
It will also print any found differences. (Older versions of Rustfmt don't
support `--check`, use `--write-mode diff`).
-A minimal Travis setup could look like this (requires Rust 1.24.0 or greater):
+A minimal Travis setup could look like this (requires Rust 1.31.0 or greater):
```yaml
language: rust
+++ /dev/null
-environment:
- global:
- PROJECT_NAME: rustfmt
-
-build: false
-
-test_script:
- - echo Why does no one have access to delete me?
## Installation
- Install [CLion](https://www.jetbrains.com/clion/), [IntelliJ Ultimate or CE](https://www.jetbrains.com/idea/) through the direct download link or using the [JetBrains Toolbox](https://www.jetbrains.com/toolbox/).
- CLion provides a built-in debugger interface but its not free like IntelliJ CE - which does not provide the debugger interface. (IntelliJ seems to lack the toolchain for that, see this discussion [intellij-rust/issues/535](https://github.com/intellij-rust/intellij-rust/issues/535))
-
-- Install the [Rust Plugin](https://intellij-rust.github.io/) by navigating to File -> Settings -> Plugins and press "Install JetBrains Plugin"
- ![plugins](https://user-images.githubusercontent.com/1133787/47240861-f40af680-d3e9-11e8-9b82-cdd5c8d5f5b8.png)
+ CLion and IntelliJ Ultimate [provide a built-in debugger interface](https://github.com/intellij-rust/intellij-rust#compatible-ides) but they are not free like IntelliJ CE.
+
+- Install the [Rust Plugin](https://intellij-rust.github.io/) by navigating to File → Settings → Plugins and searching the plugin in the Marketplace
+ ![plugins](https://user-images.githubusercontent.com/6505554/83944518-6f1e5c00-a81d-11ea-9c35-e16948811ba8.png)
-- Press "Install" on the rust plugin
- ![install rust](https://user-images.githubusercontent.com/1133787/47240803-c0c86780-d3e9-11e8-9265-22f735e4d7ed.png)
+- Press "Install" on the Rust plugin
+ ![install rust](https://user-images.githubusercontent.com/6505554/83944533-82c9c280-a81d-11ea-86b3-ee2e31bc7d12.png)
- Restart CLion/IntelliJ
## Configuration
-- Open the settings window (File -> Settings) and search for "reformat"
+### Run Rustfmt on save
+
+- Open Rustfmt settings (File → Settings → Languages & Frameworks → Rust → Rustfmt) and enable "Run rustfmt on Save"
+ ![run_rustfmt_on_save](https://user-images.githubusercontent.com/6505554/83944610-3468f380-a81e-11ea-9c34-0cbd18dd4969.png)
+
+- IntellJ uses autosave, so now your files will always be formatted according to rustfmt. Alternatively you can use Ctrl+S to reformat file manually
+
+### Bind shortcut to "Reformat File with Rustfmt" action
+
+- Open the settings window (File → Settings) and search for "reformat"
![keymap](https://user-images.githubusercontent.com/1133787/47240922-2ae10c80-d3ea-11e8-9d8f-c798d9749240.png)
- Right-click on "Reformat File with Rustfmt" and assign a keyboard shortcut
+++ /dev/null
-indent_style = "Visual"
-combine_control_expr = false
[toolchain]
-channel = "nightly-2021-10-20"
+channel = "nightly-2021-11-08"
components = ["rustc-dev"]
if next.is_doc_comment() {
let snippet = context.snippet(missing_span);
let (_, mlb) = has_newlines_before_after_comment(snippet);
- result.push_str(&mlb);
+ result.push_str(mlb);
}
}
result.push('\n');
if next.is_doc_comment() {
let snippet = context.snippet(missing_span);
let (_, mlb) = has_newlines_before_after_comment(snippet);
- result.push_str(&mlb);
+ result.push_str(mlb);
}
}
result.push('\n');
) {
assert_eq!(
expected_comment,
- format!("{}", DocCommentFormatter::new(&literal, style))
+ format!("{}", DocCommentFormatter::new(literal, style))
);
}
}
};
fn main() {
- env_logger::init();
+ env_logger::Builder::from_env("RUSTFMT_LOG").init();
let opts = make_opts();
let exit_code = match execute(&opts) {
fn get_targets_recursive(
manifest_path: Option<&Path>,
- mut targets: &mut BTreeSet<Target>,
+ targets: &mut BTreeSet<Target>,
visited: &mut BTreeSet<String>,
) -> Result<(), io::Error> {
let metadata = get_cargo_metadata(manifest_path)?;
for package in &metadata.packages {
- add_targets(&package.targets, &mut targets);
+ add_targets(&package.targets, targets);
// Look for local dependencies using information available since cargo v1.51
// It's theoretically possible someone could use a newer version of rustfmt with
.any(|p| p.manifest_path.eq(&manifest_path))
{
visited.insert(dependency.name.to_owned());
- get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
+ get_targets_recursive(Some(&manifest_path), targets, visited)?;
}
}
}
} else {
self.rewrites
.iter()
- .map(|rw| utils::unicode_str_width(&rw))
+ .map(|rw| utils::unicode_str_width(rw))
.sum()
} + last.tries;
let one_line_budget = if self.child_count == 1 {
ChainItemKind::Comment(_, CommentPosition::Top) => result.push_str(&connector),
_ => result.push_str(&connector),
}
- result.push_str(&rewrite);
+ result.push_str(rewrite);
}
Some(result)
/// attributes are valid rust attributes
/// See <https://doc.rust-lang.org/rustdoc/print.html#attributes>
fn new(attributes: &str) -> CodeBlockAttribute {
- for attribute in attributes.split(",") {
+ for attribute in attributes.split(',') {
match attribute.trim() {
"" | "rust" | "should_panic" | "no_run" | "edition2015" | "edition2018"
| "edition2021" => (),
result.push_str(line);
result.push_str(match iter.peek() {
Some(next_line) if next_line.is_empty() => sep.trim_end(),
- Some(..) => &sep,
+ Some(..) => sep,
None => "",
});
}
let is_last = i == count_newlines(orig);
if let Some(ref mut ib) = self.item_block {
- if ib.add_line(&line) {
+ if ib.add_line(line) {
return false;
}
self.is_prev_line_multi_line = false;
self.item_block = None;
if let Some(stripped) = line.strip_prefix("```") {
self.code_block_attr = Some(CodeBlockAttribute::new(stripped))
- } else if self.fmt.config.wrap_comments() && ItemizedBlock::is_itemized_line(&line) {
- let ib = ItemizedBlock::new(&line);
+ } else if self.fmt.config.wrap_comments() && ItemizedBlock::is_itemized_line(line) {
+ let ib = ItemizedBlock::new(line);
self.item_block = Some(ib);
return false;
}
{
(&line[4..], true)
} else if let CommentStyle::Custom(opener) = *style {
- if let Some(ref stripped) = line.strip_prefix(opener) {
+ if let Some(stripped) = line.strip_prefix(opener) {
(stripped, true)
} else {
(&line[opener.trim_end().len()..], false)
None => unreachable!(),
};
- while let Some((kind, c)) = self.base.next() {
+ for (kind, c) in self.base.by_ref() {
// needed to set the kind of the ending character on the last line
self.kind = kind;
if c == '\n' {
context.parse_sess.span_to_filename(span),
vec![FormattingError::from_span(
span,
- &context.parse_sess,
+ context.parse_sess,
ErrorKind::LostComment,
)],
);
fn remove_comment_header(comment: &str) -> &str {
if comment.starts_with("///") || comment.starts_with("//!") {
&comment[3..]
- } else if let Some(ref stripped) = comment.strip_prefix("//") {
+ } else if let Some(stripped) = comment.strip_prefix("//") {
stripped
} else if (comment.starts_with("/**") && !comment.starts_with("/**/"))
|| comment.starts_with("/*!")
Windows,
/// Force CR (`\n).
Unix,
- /// `\r\n` in Windows, `\n`` on other platforms.
+ /// `\r\n` in Windows, `\n` on other platforms.
Native,
}
/// 2. other imports
/// 3. `self` / `crate` / `super` imports
StdExternalCrate,
+ /// Discard existing groups, and create a single group for everything
+ One,
}
#[config_type]
format!(r#"<file name="{}">"#, bin_file),
format!(
r#"<error line="2" severity="warning" message="Should be `{}`" />"#,
- XmlEscaped(&r#" println!("Hello, world!");"#),
+ XmlEscaped(r#" println!("Hello, world!");"#),
),
String::from("</file>"),
];
format!(r#"<file name="{}">"#, lib_file),
format!(
r#"<error line="2" severity="warning" message="Should be `{}`" />"#,
- XmlEscaped(&r#" println!("Greetings!");"#),
+ XmlEscaped(r#" println!("Greetings!");"#),
),
String::from("</file>"),
];
}: FormattedFile<'_>,
) -> Result<EmitterResult, io::Error> {
const CONTEXT_SIZE: usize = 3;
- let mismatch = make_diff(&original_text, formatted_text, CONTEXT_SIZE);
+ let mismatch = make_diff(original_text, formatted_text, CONTEXT_SIZE);
let has_diff = !mismatch.is_empty();
if has_diff {
}
_ => false,
},
- ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, &expr),
+ ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr),
_ => false,
}
}
prefix: &str,
shape: Shape,
) -> Option<String> {
- if block_has_statements(&block) {
+ if block_has_statements(block) {
return None;
}
block: &ast::Block,
attrs: Option<&[ast::Attribute]>,
) -> bool {
- !block_has_statements(&block)
+ !block_has_statements(block)
&& !block_contains_comment(context, block)
&& attrs.map_or(true, |a| inner_attributes(a).is_empty())
}
let span = lit.span;
let symbol = lit.token.symbol.as_str();
- if symbol.starts_with("0x") {
+ if let Some(symbol_stripped) = symbol.strip_prefix("0x") {
let hex_lit = match context.config.hex_literal_case() {
HexLiteralCase::Preserve => None,
- HexLiteralCase::Upper => Some(symbol[2..].to_ascii_uppercase()),
- HexLiteralCase::Lower => Some(symbol[2..].to_ascii_lowercase()),
+ HexLiteralCase::Upper => Some(symbol_stripped.to_ascii_uppercase()),
+ HexLiteralCase::Lower => Some(symbol_stripped.to_ascii_lowercase()),
};
if let Some(hex_lit) = hex_lit {
return wrap_str(
};
let fields_str =
- wrap_struct_field(context, &attrs, &fields_str, shape, v_shape, one_line_width)?;
+ wrap_struct_field(context, attrs, &fields_str, shape, v_shape, one_line_width)?;
Some(format!("{} {{{}}}", path_str, fields_str))
// FIXME if context.config.indent_style() == Visual, but we run out
shape: Shape,
rhs_tactics: RhsTactics,
) -> Option<String> {
- let last_line_width = last_line_width(&lhs).saturating_sub(if lhs.contains('\n') {
+ let last_line_width = last_line_width(lhs).saturating_sub(if lhs.contains('\n') {
shape.indent.width()
} else {
0
if contains_comment {
let rhs = rhs.trim_start();
- combine_strs_with_missing_comments(context, &lhs, &rhs, between_span, shape, allow_extend)
+ combine_strs_with_missing_comments(context, &lhs, rhs, between_span, shape, allow_extend)
} else {
Some(lhs + &rhs)
}
has_rhs_comment: bool,
) -> Option<String> {
match orig_rhs {
+ Some(ref new_str) if new_str.is_empty() => {
+ return Some(String::new());
+ }
Some(ref new_str)
if !new_str.contains('\n') && unicode_str_width(new_str) <= shape.width =>
{
}
fn main() {
- env_logger::init();
+ env_logger::Builder::from_env("RUSTFMT_LOG").init();
let opts = Opts::from_args();
if let Err(e) = run(opts) {
println!("{}", e);
let snippet_provider = self.parse_session.snippet_provider(module.span);
let mut visitor = FmtVisitor::from_parse_sess(
&self.parse_session,
- &self.config,
+ self.config,
&snippet_provider,
self.report.clone(),
);
&mut visitor.buffer,
&path,
&visitor.skipped_range.borrow(),
- &self.config,
+ self.config,
&self.report,
);
}
fn main() {
- env_logger::init();
+ env_logger::Builder::from_env("RUSTFMT_LOG").init();
let opts = make_opts();
let matches = opts
shape: Shape,
) -> Option<String> {
let vis = self.visibility.as_ref().map_or(Cow::from(""), |vis| {
- crate::utils::format_visibility(context, &vis)
+ crate::utils::format_visibility(context, vis)
});
let use_str = self
.rewrite(context, shape.offset_left(vis.len())?)
fn rewrite(&self, context: &RewriteContext<'_>, mut shape: Shape) -> Option<String> {
let mut result = String::with_capacity(256);
let mut iter = self.path.iter().peekable();
- while let Some(ref segment) = iter.next() {
+ while let Some(segment) = iter.next() {
let segment_str = segment.rewrite(context, shape)?;
result.push_str(&segment_str);
if iter.peek().is_some() {
fn to_str(&self, context: &RewriteContext<'_>) -> String {
let mut result = String::with_capacity(128);
// Vis defaultness constness unsafety abi.
- result.push_str(&*format_visibility(context, &self.visibility));
+ result.push_str(&*format_visibility(context, self.visibility));
result.push_str(format_defaultness(self.defaultness));
result.push_str(format_constness(self.constness));
result.push_str(format_async(&self.is_async));
fn need_empty_line(a: &ast::AssocItemKind, b: &ast::AssocItemKind) -> bool {
match (a, b) {
(TyAlias(lty), TyAlias(rty))
- if both_type(<y.3, &rty.3) || both_opaque(<y.3, &rty.3) =>
+ if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) =>
{
false
}
buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
(TyAlias(lty), TyAlias(rty))
- if both_type(<y.3, &rty.3) || both_opaque(<y.3, &rty.3) =>
+ if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) =>
{
a.ident.as_str().cmp(&b.ident.as_str())
}
a.ident.as_str().cmp(&b.ident.as_str())
}
(Fn(..), Fn(..)) => a.span.lo().cmp(&b.span.lo()),
- (TyAlias(ty), _) if is_type(&ty.3) => Ordering::Less,
- (_, TyAlias(ty)) if is_type(&ty.3) => Ordering::Greater,
+ (TyAlias(ty), _) if is_type(&ty.ty) => Ordering::Less,
+ (_, TyAlias(ty)) if is_type(&ty.ty) => Ordering::Greater,
(TyAlias(..), _) => Ordering::Less,
(_, TyAlias(..)) => Ordering::Greater,
(Const(..), _) => Ordering::Less,
offset: Indent,
) -> Option<String> {
if let ast::ItemKind::Impl(impl_kind) = &item.kind {
- let ast::ImplKind {
+ let ast::Impl {
ref generics,
ref self_ty,
ref items,
offset: Indent,
) -> Option<String> {
if let ast::ItemKind::Impl(impl_kind) = &item.kind {
- let ast::ImplKind {
+ let ast::Impl {
unsafety,
polarity,
defaultness,
offset: Indent,
) -> Option<String> {
if let ast::ItemKind::Trait(trait_kind) = &item.kind {
- let ast::TraitKind(is_auto, unsafety, ref generics, ref generic_bounds, ref trait_items) =
- **trait_kind;
+ let ast::Trait {
+ is_auto,
+ unsafety,
+ ref generics,
+ ref bounds,
+ ref items,
+ } = **trait_kind;
let mut result = String::with_capacity(128);
let header = format!(
"{}{}{}trait ",
result.push_str(&generics_str);
// FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
- if !generic_bounds.is_empty() {
+ if !bounds.is_empty() {
let ident_hi = context
.snippet_provider
.span_after(item.span, &item.ident.as_str());
- let bound_hi = generic_bounds.last().unwrap().span().hi();
+ let bound_hi = bounds.last().unwrap().span().hi();
let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
if contains_comment(snippet) {
return None;
result = rewrite_assign_rhs_with(
context,
result + ":",
- generic_bounds,
+ bounds,
shape,
RhsTactics::ForceNextLineWithoutIndent,
)?;
let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
let where_budget = context.budget(last_line_width(&result));
- let pos_before_where = if generic_bounds.is_empty() {
+ let pos_before_where = if bounds.is_empty() {
generics.where_clause.span.lo()
} else {
- generic_bounds[generic_bounds.len() - 1].span().hi()
+ bounds[bounds.len() - 1].span().hi()
};
let option = WhereClauseOption::snuggled(&generics_str);
let where_clause_str = rewrite_where_clause(
}
}
+ let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
+ let snippet = context.snippet(block_span);
+ let open_pos = snippet.find_uncommented("{")? + 1;
+
match context.config.brace_style() {
_ if last_line_contains_single_line_comment(&result)
|| last_line_width(&result) + 2 > context.budget(offset.width()) =>
{
result.push_str(&offset.to_string_with_newline(context.config));
}
+ _ if context.config.empty_item_single_line()
+ && items.is_empty()
+ && !result.contains('\n')
+ && !contains_comment(&snippet[open_pos..]) =>
+ {
+ result.push_str(" {}");
+ return Some(result);
+ }
BraceStyle::AlwaysNextLine => {
result.push_str(&offset.to_string_with_newline(context.config));
}
BraceStyle::PreferSameLine => result.push(' '),
BraceStyle::SameLineWhere => {
if result.contains('\n')
- || (!generics.where_clause.predicates.is_empty() && !trait_items.is_empty())
+ || (!generics.where_clause.predicates.is_empty() && !items.is_empty())
{
result.push_str(&offset.to_string_with_newline(context.config));
} else {
}
result.push('{');
- let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
- let snippet = context.snippet(block_span);
- let open_pos = snippet.find_uncommented("{")? + 1;
let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
- if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
+ if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
let mut visitor = FmtVisitor::from_context(context);
visitor.block_indent = offset.block_only().block_indent(context.config);
visitor.last_pos = block_span.lo() + BytePos(open_pos as u32);
- for item in trait_items {
+ for item in items {
visitor.visit_trait_item(item);
}
}
}
-struct OpaqueTypeBounds<'a> {
- generic_bounds: &'a ast::GenericBounds,
-}
-
-impl<'a> Rewrite for OpaqueTypeBounds<'a> {
- fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
- self.generic_bounds
- .rewrite(context, shape)
- .map(|s| format!("impl {}", s))
- }
-}
-
pub(crate) struct TraitAliasBounds<'a> {
generic_bounds: &'a ast::GenericBounds,
generics: &'a ast::Generics,
} else if fits_single_line {
Cow::from(" ")
} else {
- shape.indent.to_string_with_newline(&context.config)
+ shape.indent.to_string_with_newline(context.config)
};
Some(format!("{}{}{}", generic_bounds_str, space, where_str))
let alias = rewrite_ident(context, ident);
// 6 = "trait ", 2 = " ="
let g_shape = shape.offset_left(6)?.sub_width(2)?;
- let generics_str = rewrite_generics(context, &alias, generics, g_shape)?;
+ let generics_str = rewrite_generics(context, alias, generics, g_shape)?;
let vis_str = format_visibility(context, vis);
let lhs = format!("{}trait {} =", vis_str, generics_str);
// 1 = ";"
closer: &str,
) {
// 3 = " {}" or "();"
- let used_width = last_line_used_width(&result, offset.width()) + 3;
+ let used_width = last_line_used_width(result, offset.width()) + 3;
if used_width > context.config.max_width() {
result.push_str(&offset.to_string_with_newline(context.config))
}
Some(result)
}
-pub(crate) fn rewrite_type<R: Rewrite>(
- context: &RewriteContext<'_>,
+pub(crate) enum ItemVisitorKind<'a> {
+ Item(&'a ast::Item),
+ AssocTraitItem(&'a ast::AssocItem),
+ AssocImplItem(&'a ast::AssocItem),
+ ForeignItem(&'a ast::ForeignItem),
+}
+
+struct TyAliasRewriteInfo<'c, 'g>(
+ &'c RewriteContext<'c>,
+ Indent,
+ &'g ast::Generics,
+ symbol::Ident,
+ Span,
+);
+
+pub(crate) fn rewrite_type_alias<'a, 'b>(
+ ty_alias_kind: &ast::TyAlias,
+ context: &RewriteContext<'a>,
indent: Indent,
- ident: symbol::Ident,
- vis: &ast::Visibility,
- generics: &ast::Generics,
+ visitor_kind: &ItemVisitorKind<'b>,
+ span: Span,
+) -> Option<String> {
+ use ItemVisitorKind::*;
+
+ let ast::TyAlias {
+ defaultness,
+ ref generics,
+ ref bounds,
+ ref ty,
+ } = *ty_alias_kind;
+ let ty_opt = ty.as_ref().map(|t| &**t);
+ let (ident, vis) = match visitor_kind {
+ Item(i) => (i.ident, &i.vis),
+ AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
+ ForeignItem(i) => (i.ident, &i.vis),
+ };
+ let rw_info = &TyAliasRewriteInfo(context, indent, generics, ident, span);
+
+ // Type Aliases are formatted slightly differently depending on the context
+ // in which they appear, whether they are opaque, and whether they are associated.
+ // https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html
+ // https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases
+ match (visitor_kind, ty_opt) {
+ (Item(_), None) => {
+ let op_ty = OpaqueType { bounds };
+ rewrite_ty(rw_info, Some(bounds), Some(&op_ty), vis)
+ }
+ (Item(_), Some(ty)) => rewrite_ty(rw_info, Some(bounds), Some(&*ty), vis),
+ (AssocImplItem(_), _) => {
+ let result = if let Some(ast::Ty {
+ kind: ast::TyKind::ImplTrait(_, ref bounds),
+ ..
+ }) = ty_opt
+ {
+ let op_ty = OpaqueType { bounds };
+ rewrite_ty(rw_info, None, Some(&op_ty), &DEFAULT_VISIBILITY)
+ } else {
+ rewrite_ty(rw_info, None, ty.as_ref(), vis)
+ }?;
+ match defaultness {
+ ast::Defaultness::Default(..) => Some(format!("default {}", result)),
+ _ => Some(result),
+ }
+ }
+ (AssocTraitItem(_), _) | (ForeignItem(_), _) => {
+ rewrite_ty(rw_info, Some(bounds), ty.as_ref(), vis)
+ }
+ }
+}
+
+fn rewrite_ty<R: Rewrite>(
+ rw_info: &TyAliasRewriteInfo<'_, '_>,
generic_bounds_opt: Option<&ast::GenericBounds>,
rhs: Option<&R>,
- span: Span,
+ vis: &ast::Visibility,
) -> Option<String> {
let mut result = String::with_capacity(128);
+ let TyAliasRewriteInfo(context, indent, generics, ident, span) = *rw_info;
result.push_str(&format!("{}type ", format_visibility(context, vis)));
let ident_str = rewrite_ident(context, ident);
}
}
-pub(crate) fn rewrite_opaque_type(
- context: &RewriteContext<'_>,
- indent: Indent,
- ident: symbol::Ident,
- generic_bounds: &ast::GenericBounds,
- generics: &ast::Generics,
- vis: &ast::Visibility,
- span: Span,
-) -> Option<String> {
- let opaque_type_bounds = OpaqueTypeBounds { generic_bounds };
- rewrite_type(
- context,
- indent,
- ident,
- vis,
- generics,
- Some(generic_bounds),
- Some(&opaque_type_bounds),
- span,
- )
-}
-
fn type_annotation_spacing(config: &Config) -> (&str, &str) {
(
if config.space_before_colon() { " " } else { "" },
}
}
-pub(crate) fn rewrite_impl_type(
- ident: symbol::Ident,
- vis: &ast::Visibility,
- defaultness: ast::Defaultness,
- ty_opt: Option<&ptr::P<ast::Ty>>,
- generics: &ast::Generics,
- context: &RewriteContext<'_>,
- indent: Indent,
- span: Span,
-) -> Option<String> {
- // Opaque type
- let result = if let Some(rustc_ast::ast::Ty {
- kind: ast::TyKind::ImplTrait(_, ref bounds),
- ..
- }) = ty_opt.map(|t| &**t)
- {
- rewrite_type(
- context,
- indent,
- ident,
- &DEFAULT_VISIBILITY,
- generics,
- None,
- Some(&OpaqueType { bounds }),
- span,
- )
- } else {
- rewrite_type(context, indent, ident, vis, generics, None, ty_opt, span)
- }?;
-
- match defaultness {
- ast::Defaultness::Default(..) => Some(format!("default {}", result)),
- _ => Some(result),
- }
-}
-
impl Rewrite for ast::FnRetTy {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
match *self {
)?;
Some(combine_strs_with_missing_comments(
context,
- ¶m_attrs,
+ param_attrs,
&format!("&{} {}self", lifetime_str, mut_str),
span,
shape,
}
None => Some(combine_strs_with_missing_comments(
context,
- ¶m_attrs,
+ param_attrs,
&format!("&{}self", mut_str),
span,
shape,
Some(combine_strs_with_missing_comments(
context,
- ¶m_attrs,
+ param_attrs,
&format!("{}self: {}", format_mutability(mutability), type_str),
span,
shape,
}
ast::SelfKind::Value(mutability) => Some(combine_strs_with_missing_comments(
context,
- ¶m_attrs,
+ param_attrs,
&format!("{}self", format_mutability(mutability)),
span,
shape,
}
// Skip `pub(crate)`.
- let lo_after_visibility = get_bytepos_after_visibility(&fn_sig.visibility, span);
+ let lo_after_visibility = get_bytepos_after_visibility(fn_sig.visibility, span);
// A conservative estimation, the goal is to be over all parens in generics
let params_start = fn_sig
.generics
let mut result = String::with_capacity(128);
let shape = Shape::indented(offset, context.config);
- result.push_str(&format_visibility(context, vis).trim());
+ result.push_str(format_visibility(context, vis).trim());
// Check for a missing comment between the visibility and the item name.
let after_vis = vis.span.hi();
}
}
- result.push_str(&rewrite_ident(context, ident));
+ result.push_str(rewrite_ident(context, ident));
result
}
let item_str = match self.kind {
ast::ForeignItemKind::Fn(ref fn_kind) => {
- let ast::FnKind(defaultness, ref fn_sig, ref generics, ref block) = **fn_kind;
- if let Some(ref body) = block {
+ let ast::Fn {
+ defaultness,
+ ref sig,
+ ref generics,
+ ref body,
+ } = **fn_kind;
+ if let Some(ref body) = body {
let mut visitor = FmtVisitor::from_context(context);
visitor.block_indent = shape.indent;
visitor.last_pos = self.span.lo();
let inner_attrs = inner_attributes(&self.attrs);
let fn_ctxt = visit::FnCtxt::Foreign;
visitor.visit_fn(
- visit::FnKind::Fn(fn_ctxt, self.ident, &fn_sig, &self.vis, Some(body)),
+ visit::FnKind::Fn(fn_ctxt, self.ident, &sig, &self.vis, Some(body)),
generics,
- &fn_sig.decl,
+ &sig.decl,
self.span,
defaultness,
Some(&inner_attrs),
context,
shape.indent,
self.ident,
- &FnSig::from_method_sig(&fn_sig, generics, &self.vis),
+ &FnSig::from_method_sig(&sig, generics, &self.vis),
span,
FnBraceStyle::None,
)
// 1 = ;
rewrite_assign_rhs(context, prefix, &**ty, shape.sub_width(1)?).map(|s| s + ";")
}
- ast::ForeignItemKind::TyAlias(ref ty_alias_kind) => {
- let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
- **ty_alias_kind;
- rewrite_type(
- &context,
- shape.indent,
- self.ident,
- &self.vis,
- generics,
- Some(generic_bounds),
- type_default.as_ref(),
- self.span,
- )
+ ast::ForeignItemKind::TyAlias(ref ty_alias) => {
+ let (kind, span) = (&ItemVisitorKind::ForeignItem(&self), self.span);
+ rewrite_type_alias(ty_alias, context, shape.indent, kind, span)
}
ast::ForeignItemKind::MacCall(ref mac) => {
rewrite_macro(mac, None, context, shape, MacroPosition::Item)
combine_strs_with_missing_comments(
context,
&attrs_str,
- &item_str,
+ item_str,
missed_span,
shape,
allow_extend,
writeln!(
t,
"{}",
- FormatReportFormatterBuilder::new(&self)
+ FormatReportFormatterBuilder::new(self)
.enable_colors(true)
.build()
)?;
impl fmt::Display for FormatReport {
// Prints all the formatting errors.
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- write!(fmt, "{}", FormatReportFormatterBuilder::new(&self).build())?;
+ write!(fmt, "{}", FormatReportFormatterBuilder::new(self).build())?;
Ok(())
}
}
result.push('\n');
result.push_str(indent_str);
// This is the width of the item (without comments).
- line_len = item.item.as_ref().map_or(0, |s| unicode_str_width(&s));
+ line_len = item.item.as_ref().map_or(0, |s| unicode_str_width(s));
}
} else {
result.push(' ')
pub(crate) fn total_item_width(item: &ListItem) -> usize {
comment_len(item.pre_comment.as_ref().map(|x| &(*x)[..]))
+ comment_len(item.post_comment.as_ref().map(|x| &(*x)[..]))
- + item.item.as_ref().map_or(0, |s| unicode_str_width(&s))
+ + item.item.as_ref().map_or(0, |s| unicode_str_width(s))
}
fn comment_len(comment: Option<&str>) -> usize {
})
.unwrap_or(false);
if is_like_block_indent_style {
- return trim_left_preserve_layout(context.snippet(span), indent, &context.config);
+ return trim_left_preserve_layout(context.snippet(span), indent, context.config);
}
context.skipped_range.borrow_mut().push((
// the `macro_name!` and `{ /* macro_body */ }` but skip modifying
// anything in between the braces (for now).
let snippet = context.snippet(mac.span()).trim_start_matches(|c| c != '{');
- match trim_left_preserve_layout(snippet, shape.indent, &context.config) {
+ match trim_left_preserve_layout(snippet, shape.indent, context.config) {
Some(macro_body) => Some(format!("{} {}", macro_name, macro_body)),
None => Some(format!("{} {}", macro_name, snippet)),
}
break;
}
TokenTree::Token(ref t) => {
- buffer.push_str(&pprust::token_to_string(&t));
+ buffer.push_str(&pprust::token_to_string(t));
}
_ => return None,
}
let mut iter = args.iter().peekable();
let indent_str = shape.indent.to_string_with_newline(context.config);
- while let Some(ref arg) = iter.next() {
+ while let Some(arg) = iter.next() {
result.push_str(&arg.rewrite(context, shape, use_multiple_lines)?);
if use_multiple_lines
result.pop();
}
result.push_str(&indent_str);
- } else if let Some(ref next_arg) = iter.peek() {
+ } else if let Some(next_arg) = iter.peek() {
let space_before_dollar =
!arg.kind.ends_with_space() && next_arg.kind.starts_with_dollar();
let space_before_brace = next_arg.kind.starts_with_brace();
{
s += &indent_str;
}
- (s + l + "\n", indent_next_line(kind, &l, &config))
+ (s + l + "\n", indent_next_line(kind, l, &config))
},
)
.0;
MacroArg::Item(item) => item,
_ => return None,
};
- visitor.visit_item(&item);
+ visitor.visit_item(item);
}
let mut result = String::with_capacity(256);
- result.push_str(¯o_name);
+ result.push_str(macro_name);
result.push_str(opener);
result.push_str(&visitor.block_indent.to_string_with_newline(context.config));
result.push_str(visitor.buffer.trim());
.map(|a| {
context
.snippet(a.pat.span)
- .starts_with("|")
+ .starts_with('|')
.then(|| a.pat.span().lo())
})
.collect()
let can_extend =
|expr| !context.config.force_multiline_blocks() && can_flatten_block_around_this(expr);
- if let Some(ref block) = block_can_be_flattened(context, body) {
+ if let Some(block) = block_can_be_flattened(context, body) {
if let ast::StmtKind::Expr(ref expr) = block.stmts[0].kind {
if let ast::ExprKind::Block(..) = expr.kind {
flatten_arm_body(context, expr, None)
if comment_str.is_empty() {
String::new()
} else {
- rewrite_comment(comment_str, false, shape, &context.config)?
+ rewrite_comment(comment_str, false, shape, context.config)?
}
};
result.push_str(&arrow_comment);
}
result.push_str(&nested_indent_str);
- result.push_str(&body_str);
- result.push_str(&comma);
+ result.push_str(body_str);
+ result.push_str(comma);
return Some(result);
}
result.push_str(&arrow_comment);
}
result.push_str(&block_sep);
- result.push_str(&body_str);
+ result.push_str(body_str);
result.push_str(&body_suffix);
Some(result)
};
Directory, DirectoryOwnership, ModError, ModulePathSuccess, Parser, ParserError,
};
use crate::syntux::session::ParseSess;
-use crate::utils::contains_skip;
+use crate::utils::{contains_skip, mk_sp};
mod visitor;
self.visit_mod_from_ast(&krate.items)?;
}
+ let snippet_provider = self.parse_sess.snippet_provider(krate.span);
+
self.file_map.insert(
root_filename,
Module::new(
- krate.span,
+ mk_sp(snippet_provider.start_pos(), snippet_provider.end_pos()),
None,
Cow::Borrowed(&krate.items),
Cow::Borrowed(&krate.attrs),
/// Visit modules from AST.
fn visit_mod_from_ast(
&mut self,
- items: &'ast Vec<rustc_ast::ptr::P<ast::Item>>,
+ items: &'ast [rustc_ast::ptr::P<ast::Item>],
) -> Result<(), ModuleResolutionError> {
for item in items {
if is_cfg_if(item) {
};
self.visit_sub_mod_after_directory_update(sub_mod, Some(directory))
}
- SubModKind::Internal(ref item) => {
+ SubModKind::Internal(item) => {
self.push_inline_mod_directory(item.ident, &item.attrs);
self.visit_sub_mod_after_directory_update(sub_mod, None)
}
}
match (sub_mod.ast_mod_kind, sub_mod.items) {
(Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => {
- self.visit_mod_from_ast(&items)
+ self.visit_mod_from_ast(items)
+ }
+ (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => {
+ self.visit_mod_outside_ast(items)
}
- (Some(Cow::Owned(..)), Cow::Owned(items)) => self.visit_mod_outside_ast(items),
(_, _) => Ok(()),
}
}
) -> Option<String> {
let last_item = self.last_item()?;
let rewrite = match last_item {
- OverflowableItem::Expr(ref expr) => {
+ OverflowableItem::Expr(expr) => {
match expr.kind {
// When overflowing the closure which consists of a single control flow
// expression, force to use block if its condition uses multi line.
for ((_, rewrite), s) in list.list.iter().zip(list.separators.iter()) {
if let Some(rewrite) = rewrite {
- if !is_single_line(&rewrite) || result.len() > shape.width {
+ if !is_single_line(rewrite) || result.len() > shape.width {
return None;
}
- result.push_str(&rewrite);
+ result.push_str(rewrite);
result.push(' ');
result.push_str(s);
result.push(' ');
shape: Shape,
context: &RewriteContext<'_>,
) -> Option<String> {
- let rhs_offset = shape.rhs_overhead(&context.config);
+ let rhs_offset = shape.rhs_overhead(context.config);
let nested_shape = (match context.config.indent_style() {
IndentStyle::Visual => shape.visual_indent(0),
IndentStyle::Block => shape.block_indent(context.config.tab_spaces()),
})
- .with_max_width(&context.config)
+ .with_max_width(context.config)
.sub_width(rhs_offset)?;
let indent_str = nested_shape.indent.to_string_with_newline(context.config);
let mut result = String::new();
- result.push_str(&list.list[0].1.as_ref()?);
+ result.push_str(list.list[0].1.as_ref()?);
for ((e, default_rw), s) in list.list[1..].iter().zip(list.separators.iter()) {
// The following test checks if we should keep two subexprs on the same
}
}
- result.push_str(&default_rw.as_ref()?);
+ result.push_str(default_rw.as_ref()?);
}
Some(result)
}
return node.rewrite(context, shape);
}
let nested_overhead = sep + 1;
- let rhs_offset = shape.rhs_overhead(&context.config);
+ let rhs_offset = shape.rhs_overhead(context.config);
let nested_shape = (match context.config.indent_style() {
IndentStyle::Visual => shape.visual_indent(0),
IndentStyle::Block => shape.block_indent(context.config.tab_spaces()),
})
- .with_max_width(&context.config)
+ .with_max_width(context.config)
.sub_width(rhs_offset)?;
let default_shape = match context.config.binop_separator() {
SeparatorPlace::Back => nested_shape.sub_width(nested_overhead)?,
context: &RewriteContext<'_>,
shape: Shape,
) -> Option<String> {
- let mut pat_vec: Vec<_> = pats.iter().map(|x| TuplePatField::Pat(x)).collect();
-
- if pat_vec.is_empty() {
+ if pats.is_empty() {
return Some(format!("{}()", path_str.unwrap_or_default()));
}
+ let mut pat_vec: Vec<_> = pats.iter().map(TuplePatField::Pat).collect();
+
let wildcard_suffix_len = count_wildcard_suffix_len(context, &pat_vec, span, shape);
let (pat_vec, span) = if context.config.condense_wildcard_suffixes() && wildcard_suffix_len >= 2
{
let path_str = path_str.unwrap_or_default();
overflow::rewrite_with_parens(
- &context,
+ context,
&path_str,
pat_vec.iter(),
shape,
};
let mut regrouped_items = match context.config.group_imports() {
- GroupImportsTactic::Preserve => vec![normalized_items],
+ GroupImportsTactic::Preserve | GroupImportsTactic::One => {
+ vec![normalized_items]
+ }
GroupImportsTactic::StdExternalCrate => group_imports(normalized_items),
};
span: Span,
) -> Result<(Vec<ast::Attribute>, Vec<ptr::P<ast::Item>>, Span), ParserError> {
let result = catch_unwind(AssertUnwindSafe(|| {
- let mut parser = new_parser_from_file(sess.inner(), &path, Some(span));
+ let mut parser = new_parser_from_file(sess.inner(), path, Some(span));
match parser.parse_mod(&TokenKind::Eof) {
Ok(result) => Some(result),
Err(mut e) => {
}
}));
match result {
- Ok(Some(m)) => {
- if !sess.has_errors() {
- return Ok(m);
- }
-
- if sess.can_reset_errors() {
- sess.reset_errors();
- return Ok(m);
- }
- Err(ParserError::ParseError)
+ Ok(Some(m)) if !sess.has_errors() => Ok(m),
+ Ok(Some(m)) if sess.can_reset_errors() => {
+ sess.reset_errors();
+ Ok(m)
}
- Ok(None) => Err(ParserError::ParseError),
+ Ok(_) => Err(ParserError::ParseError),
Err(..) if path.exists() => Err(ParserError::ParseError),
Err(_) => Err(ParserError::ParsePanicError),
}
}
pub(crate) fn ignore_file(&self, path: &FileName) -> bool {
- self.ignore_path_set.as_ref().is_match(&path)
+ self.ignore_path_set.as_ref().is_match(path)
}
pub(crate) fn set_silent_emitter(&mut self) {
debug!("Testing '{}'...", file_name.display());
- match idempotent_check(&file_name, &opt_config) {
+ match idempotent_check(&file_name, opt_config) {
Ok(ref report) if report.has_warnings() => {
- print!("{}", FormatReportFormatterBuilder::new(&report).build());
+ print!("{}", FormatReportFormatterBuilder::new(report).build());
fails += 1;
}
Ok(report) => reports.push(report),
use crate::{FileName, Input, Session};
-#[test]
-fn nested_out_of_line_mods_loaded() {
- // See also https://github.com/rust-lang/rustfmt/issues/4874
- let filename = "tests/mod-resolver/issue-4874/main.rs";
- let input_file = PathBuf::from(filename);
+fn verify_mod_resolution(input_file_name: &str, exp_misformatted_files: &[&str]) {
+ let input_file = PathBuf::from(input_file_name);
let config = read_config(&input_file);
let mut session = Session::<io::Stdout>::new(config, None);
let report = session
- .format(Input::File(filename.into()))
+ .format(Input::File(input_file_name.into()))
.expect("Should not have had any execution errors");
let errors_by_file = &report.internal.borrow().0;
- assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from(
- "tests/mod-resolver/issue-4874/bar/baz.rs",
- ))));
- assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from(
- "tests/mod-resolver/issue-4874/foo/qux.rs",
- ))));
+ for exp_file in exp_misformatted_files {
+ assert!(errors_by_file.contains_key(&FileName::Real(PathBuf::from(exp_file))));
+ }
+}
+
+#[test]
+fn nested_out_of_line_mods_loaded() {
+ // See also https://github.com/rust-lang/rustfmt/issues/4874
+ verify_mod_resolution(
+ "tests/mod-resolver/issue-4874/main.rs",
+ &[
+ "tests/mod-resolver/issue-4874/bar/baz.rs",
+ "tests/mod-resolver/issue-4874/foo/qux.rs",
+ ],
+ );
+}
+
+#[test]
+fn out_of_line_nested_inline_within_out_of_line() {
+ // See also https://github.com/rust-lang/rustfmt/issues/5063
+ verify_mod_resolution(
+ "tests/mod-resolver/issue-5063/main.rs",
+ &[
+ "tests/mod-resolver/issue-5063/foo/bar/baz.rs",
+ "tests/mod-resolver/issue-5063/foo.rs",
+ ],
+ );
}
result = combine_strs_with_missing_comments(
context,
result.trim_end(),
- &mt.ty.rewrite(&context, shape)?,
+ &mt.ty.rewrite(context, shape)?,
before_ty_span,
shape,
true,
let budget = shape.width.checked_sub(used_width)?;
let ty_str = mt
.ty
- .rewrite(&context, Shape::legacy(budget, shape.indent + used_width))?;
+ .rewrite(context, Shape::legacy(budget, shape.indent + used_width))?;
result.push_str(&ty_str);
}
(
VisibilityKind::Restricted { path: p, .. },
VisibilityKind::Restricted { path: q, .. },
- ) => pprust::path_to_string(&p) == pprust::path_to_string(&q),
+ ) => pprust::path_to_string(p) == pprust::path_to_string(q),
(VisibilityKind::Public, VisibilityKind::Public)
| (VisibilityKind::Inherited, VisibilityKind::Inherited)
| (
#[test]
fn test_remove_trailing_white_spaces() {
let s = " r#\"\n test\n \"#";
- assert_eq!(remove_trailing_white_spaces(&s), s);
+ assert_eq!(remove_trailing_white_spaces(s), s);
}
#[test]
let config = Config::default();
let indent = Indent::new(4, 0);
assert_eq!(
- trim_left_preserve_layout(&s, indent, &config),
+ trim_left_preserve_layout(s, indent, &config),
Some("aaa\n bbb\n ccc".to_string())
);
}
use crate::coverage::transform_missing_snippet;
use crate::items::{
format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate,
- rewrite_impl_type, rewrite_opaque_type, rewrite_type, FnBraceStyle, FnSig, StaticParts,
- StructParts,
+ rewrite_type_alias, FnBraceStyle, FnSig, ItemVisitorKind, StaticParts, StructParts,
};
use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition};
use crate::modules::Module;
);
} else {
let shape = self.shape();
- let rewrite = self.with_context(|ctx| stmt.rewrite(&ctx, shape));
+ let rewrite = self.with_context(|ctx| stmt.rewrite(ctx, shape));
self.push_rewrite(stmt.span(), rewrite)
}
}
let comment_snippet = self.snippet(span);
- let align_to_right = if unindent_comment && contains_comment(&comment_snippet) {
+ let align_to_right = if unindent_comment && contains_comment(comment_snippet) {
let first_lines = comment_snippet.splitn(2, '/').next().unwrap_or("");
- last_line_width(first_lines) > last_line_width(&comment_snippet)
+ last_line_width(first_lines) > last_line_width(comment_snippet)
} else {
false
};
let filtered_attrs;
let mut attrs = &item.attrs;
let skip_context_saved = self.skip_context.clone();
- self.skip_context.update_with_attrs(&attrs);
+ self.skip_context.update_with_attrs(attrs);
let should_visit_node_again = match item.kind {
// For use/extern crate items, skip rewriting attributes but check for a skip attribute.
ast::ItemKind::Use(ref tree) => self.format_import(item, tree),
ast::ItemKind::Impl { .. } => {
let block_indent = self.block_indent;
- let rw = self.with_context(|ctx| format_impl(&ctx, item, block_indent));
+ let rw = self.with_context(|ctx| format_impl(ctx, item, block_indent));
self.push_rewrite(item.span, rw);
}
ast::ItemKind::Trait(..) => {
let block_indent = self.block_indent;
- let rw = self.with_context(|ctx| format_trait(&ctx, item, block_indent));
+ let rw = self.with_context(|ctx| format_trait(ctx, item, block_indent));
self.push_rewrite(item.span, rw);
}
ast::ItemKind::TraitAlias(ref generics, ref generic_bounds) => {
self.visit_static(&StaticParts::from_item(item));
}
ast::ItemKind::Fn(ref fn_kind) => {
- let ast::FnKind(defaultness, ref fn_signature, ref generics, ref block) =
- **fn_kind;
- if let Some(ref body) = block {
+ let ast::Fn {
+ defaultness,
+ ref sig,
+ ref generics,
+ ref body,
+ } = **fn_kind;
+ if let Some(ref body) = body {
let inner_attrs = inner_attributes(&item.attrs);
- let fn_ctxt = match fn_signature.header.ext {
+ let fn_ctxt = match sig.header.ext {
ast::Extern::None => visit::FnCtxt::Free,
_ => visit::FnCtxt::Foreign,
};
self.visit_fn(
- visit::FnKind::Fn(
- fn_ctxt,
- item.ident,
- &fn_signature,
- &item.vis,
- Some(body),
- ),
+ visit::FnKind::Fn(fn_ctxt, item.ident, &sig, &item.vis, Some(body)),
generics,
- &fn_signature.decl,
+ &sig.decl,
item.span,
defaultness,
Some(&inner_attrs),
} else {
let indent = self.block_indent;
let rewrite = self.rewrite_required_fn(
- indent,
- item.ident,
- &fn_signature,
- &item.vis,
- generics,
- item.span,
+ indent, item.ident, &sig, &item.vis, generics, item.span,
);
self.push_rewrite(item.span, rewrite);
}
}
- ast::ItemKind::TyAlias(ref alias_kind) => {
- let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref ty) =
- **alias_kind;
- match ty {
- Some(ty) => {
- let rewrite = rewrite_type(
- &self.get_context(),
- self.block_indent,
- item.ident,
- &item.vis,
- generics,
- Some(generic_bounds),
- Some(&*ty),
- item.span,
- );
- self.push_rewrite(item.span, rewrite);
- }
- None => {
- let rewrite = rewrite_opaque_type(
- &self.get_context(),
- self.block_indent,
- item.ident,
- generic_bounds,
- generics,
- &item.vis,
- item.span,
- );
- self.push_rewrite(item.span, rewrite);
- }
- }
+ ast::ItemKind::TyAlias(ref ty_alias) => {
+ use ItemVisitorKind::Item;
+ self.visit_ty_alias_kind(ty_alias, &Item(&item), item.span);
}
ast::ItemKind::GlobalAsm(..) => {
let snippet = Some(self.snippet(item.span).to_owned());
self.skip_context = skip_context_saved;
}
- pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) {
- skip_out_of_file_lines_range_visitor!(self, ti.span);
+ fn visit_ty_alias_kind(
+ &mut self,
+ ty_kind: &ast::TyAlias,
+ visitor_kind: &ItemVisitorKind<'_>,
+ span: Span,
+ ) {
+ let rewrite = rewrite_type_alias(
+ ty_kind,
+ &self.get_context(),
+ self.block_indent,
+ visitor_kind,
+ span,
+ );
+ self.push_rewrite(span, rewrite);
+ }
+
+ fn visit_assoc_item(&mut self, visitor_kind: &ItemVisitorKind<'_>) {
+ use ItemVisitorKind::*;
+ // TODO(calebcartwright): Not sure the skip spans are correct
+ let (ai, skip_span, assoc_ctxt) = match visitor_kind {
+ AssocTraitItem(ai) => (*ai, ai.span(), visit::AssocCtxt::Trait),
+ AssocImplItem(ai) => (*ai, ai.span, visit::AssocCtxt::Impl),
+ _ => unreachable!(),
+ };
+ skip_out_of_file_lines_range_visitor!(self, ai.span);
- if self.visit_attrs(&ti.attrs, ast::AttrStyle::Outer) {
- self.push_skipped_with_span(ti.attrs.as_slice(), ti.span(), ti.span());
+ if self.visit_attrs(&ai.attrs, ast::AttrStyle::Outer) {
+ self.push_skipped_with_span(&ai.attrs.as_slice(), skip_span, skip_span);
return;
}
// TODO(calebcartwright): consider enabling box_patterns feature gate
- match ti.kind {
- ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_trait_item(ti)),
- ast::AssocItemKind::Fn(ref fn_kind) => {
- let ast::FnKind(defaultness, ref sig, ref generics, ref block) = **fn_kind;
- if let Some(ref body) = block {
- let inner_attrs = inner_attributes(&ti.attrs);
- let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Trait);
+ match (&ai.kind, visitor_kind) {
+ (ast::AssocItemKind::Const(..), AssocTraitItem(_)) => {
+ self.visit_static(&StaticParts::from_trait_item(&ai))
+ }
+ (ast::AssocItemKind::Const(..), AssocImplItem(_)) => {
+ self.visit_static(&StaticParts::from_impl_item(&ai))
+ }
+ (ast::AssocItemKind::Fn(ref fn_kind), _) => {
+ let ast::Fn {
+ defaultness,
+ ref sig,
+ ref generics,
+ ref body,
+ } = **fn_kind;
+ if let Some(ref body) = body {
+ let inner_attrs = inner_attributes(&ai.attrs);
+ let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
self.visit_fn(
- visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &ti.vis, Some(body)),
+ visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, Some(body)),
generics,
&sig.decl,
- ti.span,
+ ai.span,
defaultness,
Some(&inner_attrs),
);
} else {
let indent = self.block_indent;
let rewrite =
- self.rewrite_required_fn(indent, ti.ident, sig, &ti.vis, generics, ti.span);
- self.push_rewrite(ti.span, rewrite);
+ self.rewrite_required_fn(indent, ai.ident, sig, &ai.vis, generics, ai.span);
+ self.push_rewrite(ai.span, rewrite);
}
}
- ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
- let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
- **ty_alias_kind;
- let rewrite = rewrite_type(
- &self.get_context(),
- self.block_indent,
- ti.ident,
- &ti.vis,
- generics,
- Some(generic_bounds),
- type_default.as_ref(),
- ti.span,
- );
- self.push_rewrite(ti.span, rewrite);
+ (ast::AssocItemKind::TyAlias(ref ty_alias), _) => {
+ self.visit_ty_alias_kind(ty_alias, visitor_kind, ai.span);
}
- ast::AssocItemKind::MacCall(ref mac) => {
- self.visit_mac(mac, Some(ti.ident), MacroPosition::Item);
+ (ast::AssocItemKind::MacCall(ref mac), _) => {
+ self.visit_mac(mac, Some(ai.ident), MacroPosition::Item);
}
+ _ => unreachable!(),
}
}
- pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) {
- skip_out_of_file_lines_range_visitor!(self, ii.span);
-
- if self.visit_attrs(&ii.attrs, ast::AttrStyle::Outer) {
- self.push_skipped_with_span(ii.attrs.as_slice(), ii.span, ii.span);
- return;
- }
+ pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) {
+ self.visit_assoc_item(&ItemVisitorKind::AssocTraitItem(ti));
+ }
- match ii.kind {
- ast::AssocItemKind::Fn(ref fn_kind) => {
- let ast::FnKind(defaultness, ref sig, ref generics, ref block) = **fn_kind;
- if let Some(ref body) = block {
- let inner_attrs = inner_attributes(&ii.attrs);
- let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Impl);
- self.visit_fn(
- visit::FnKind::Fn(fn_ctxt, ii.ident, sig, &ii.vis, Some(body)),
- generics,
- &sig.decl,
- ii.span,
- defaultness,
- Some(&inner_attrs),
- );
- } else {
- let indent = self.block_indent;
- let rewrite =
- self.rewrite_required_fn(indent, ii.ident, sig, &ii.vis, generics, ii.span);
- self.push_rewrite(ii.span, rewrite);
- }
- }
- ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_impl_item(ii)),
- ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
- let ast::TyAliasKind(defaultness, ref generics, _, ref ty) = **ty_alias_kind;
- self.push_rewrite(
- ii.span,
- rewrite_impl_type(
- ii.ident,
- &ii.vis,
- defaultness,
- ty.as_ref(),
- &generics,
- &self.get_context(),
- self.block_indent,
- ii.span,
- ),
- );
- }
- ast::AssocItemKind::MacCall(ref mac) => {
- self.visit_mac(mac, Some(ii.ident), MacroPosition::Item);
- }
- }
+ pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) {
+ self.visit_assoc_item(&ItemVisitorKind::AssocImplItem(ii));
}
fn visit_mac(&mut self, mac: &ast::MacCall, ident: Option<symbol::Ident>, pos: MacroPosition) {
}
fn walk_mod_items(&mut self, items: &[rustc_ast::ptr::P<ast::Item>]) {
- self.visit_items_with_reordering(&ptr_vec_to_ref_vec(&items));
+ self.visit_items_with_reordering(&ptr_vec_to_ref_vec(items));
}
fn walk_stmts(&mut self, stmts: &[Stmt<'_>], include_current_empty_semi: bool) {
--- /dev/null
+mod bar {
+ mod baz;}
\ No newline at end of file
--- /dev/null
+fn baz() { }
\ No newline at end of file
--- /dev/null
+fn main() {
+ println!("Hello, world!");
+}
+
+mod foo;
\ No newline at end of file
--- /dev/null
+// rustfmt-group_imports: One
+// rustfmt-imports_granularity: Crate
+use chrono::Utc;
+use super::update::convert_publish_payload;
+
+use juniper::{FieldError, FieldResult};
+use uuid::Uuid;
+use alloc::alloc::Layout;
+
+use std::sync::Arc;
+use alloc::vec::Vec;
+
+use broker::database::PooledConnection;
+
+use super::schema::{Context, Payload};
+use core::f32;
+use crate::models::Event;
--- /dev/null
+// rustfmt-group_imports: One
+mod test {
+ use crate::foo::bar;
+
+ use std::path;
+ use crate::foo::bar2;
+}
--- /dev/null
+// rustfmt-group_imports: One
+// rustfmt-reorder_imports: false
+use chrono::Utc;
+use super::update::convert_publish_payload;
+
+use juniper::{FieldError, FieldResult};
+use uuid::Uuid;
+use alloc::alloc::Layout;
+
+use std::sync::Arc;
+
+use broker::database::PooledConnection;
+
+use super::schema::{Context, Payload};
+use core::f32;
+use crate::models::Event;
--- /dev/null
+// rustfmt-group_imports: One
+use chrono::Utc;
+use super::update::convert_publish_payload;
+
+use juniper::{FieldError, FieldResult};
+use uuid::Uuid;
+use alloc::alloc::Layout;
+
+use std::sync::Arc;
+
+use broker::database::PooledConnection;
+
+use super::schema::{Context, Payload};
+use core::f32;
+use crate::models::Event;
--- /dev/null
+// rustfmt-brace_style: AlwaysNextLine
+// rustfmt-empty_item_single_line: false
+
+fn function()
+{
+
+}
+
+struct Struct
+{
+
+}
+
+enum Enum
+{
+
+}
+
+trait Trait
+{
+
+}
+
+impl<T> Trait for T
+{
+
+}
+
+trait Trait2<T>
+where
+ T: Copy + Display + Write + Read + FromStr, {}
+
+trait Trait3<T>
+where
+ T: Something
+ + SomethingElse
+ + Sync
+ + Send
+ + Display
+ + Debug
+ + Copy
+ + Hash
+ + Debug
+ + Display
+ + Write
+ + Read, {}
struct D<T> where T: Copy {}
}
+
+
+fn function()
+{
+
+}
+
+trait Trait
+{
+
+}
+
+impl<T> Trait for T
+{
+
+}
+
+trait Trait2<T>
+where
+ T: Copy + Display + Write + Read + FromStr, {}
+
+trait Trait3<T>
+where
+ T: Something
+ + SomethingElse
+ + Sync
+ + Send
+ + Display
+ + Debug
+ + Copy
+ + Hash
+ + Debug
+ + Display
+ + Write
+ + Read, {}
--- /dev/null
+// rustfmt-group_imports: One
+// rustfmt-imports_granularity: Crate
+use super::{
+ schema::{Context, Payload},
+ update::convert_publish_payload,
+};
+use crate::models::Event;
+use alloc::{alloc::Layout, vec::Vec};
+use broker::database::PooledConnection;
+use chrono::Utc;
+use core::f32;
+use juniper::{FieldError, FieldResult};
+use std::sync::Arc;
+use uuid::Uuid;
--- /dev/null
+// rustfmt-group_imports: One
+mod test {
+ use crate::foo::bar;
+ use crate::foo::bar2;
+ use std::path;
+}
--- /dev/null
+// rustfmt-group_imports: One
+// rustfmt-reorder_imports: false
+use chrono::Utc;
+use super::update::convert_publish_payload;
+use juniper::{FieldError, FieldResult};
+use uuid::Uuid;
+use alloc::alloc::Layout;
+use std::sync::Arc;
+use broker::database::PooledConnection;
+use super::schema::{Context, Payload};
+use core::f32;
+use crate::models::Event;
--- /dev/null
+// rustfmt-group_imports: One
+use super::schema::{Context, Payload};
+use super::update::convert_publish_payload;
+use crate::models::Event;
+use alloc::alloc::Layout;
+use broker::database::PooledConnection;
+use chrono::Utc;
+use core::f32;
+use juniper::{FieldError, FieldResult};
+use std::sync::Arc;
+use uuid::Uuid;
--- /dev/null
+// rustfmt-brace_style: AlwaysNextLine
+// rustfmt-empty_item_single_line: false
+
+fn function()
+{
+}
+
+struct Struct {}
+
+enum Enum {}
+
+trait Trait
+{
+}
+
+impl<T> Trait for T
+{
+}
+
+trait Trait2<T>
+where
+ T: Copy + Display + Write + Read + FromStr,
+{
+}
+
+trait Trait3<T>
+where
+ T: Something
+ + SomethingElse
+ + Sync
+ + Send
+ + Display
+ + Debug
+ + Copy
+ + Hash
+ + Debug
+ + Display
+ + Write
+ + Read,
+{
+}
--- /dev/null
+// rustfmt-trailing_comma: Always
+
+pub struct Matrix<T, const R: usize, const C: usize,>
+where
+ [T; R * C]:,
+{
+ contents: [T; R * C],
+}
--- /dev/null
+// rustfmt-trailing_comma: Never
+
+pub struct Matrix<T, const R: usize, const C: usize>
+where
+ [T; R * C]:
+{
+ contents: [T; R * C]
+}
--- /dev/null
+// leading comment
+
+#![rustfmt::skip]
+fn main() {
+ println!("main"); // commented
+}
+
+// post comment
--- /dev/null
+#![rustfmt::skip]
+
+mod a {
+ mod b {
+
+ }
+
+ // trailing comment b
+}
+
+// trailing comment a
--- /dev/null
+impl ThisIsALongStructNameToPushTheWhereToWrapLolololol where
+ [(); this_is_a_long_const_function_name()]:
+{
+}
where
T: Copy, {}
}
+
+fn function() {}
+
+trait Trait {}
+
+impl<T> Trait for T {}
+
+trait Trait2<T>
+where
+ T: Copy + Display + Write + Read + FromStr,
+{
+}
+
+trait Trait3<T>
+where
+ T: Something
+ + SomethingElse
+ + Sync
+ + Send
+ + Display
+ + Debug
+ + Copy
+ + Hash
+ + Debug
+ + Display
+ + Write
+ + Read,
+{
+}
&mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
&mut |entry, contents| {
let file = entry.path();
- let filestr = file.to_string_lossy().replace("\\", "/");
let filename = file.file_name().unwrap();
if filename != "Cargo.toml" {
return;
}
// Library crates are not yet ready to migrate to 2021.
- //
- // The reference and rustc-dev-guide are submodules, so are left at
- // 2018 for now. They should be removed from this exception list
- // when bumped.
- if path.components().any(|c| c.as_os_str() == "library")
- || filestr.contains("src/doc/reference/style-check/Cargo.toml")
- || filestr.contains("src/doc/rustc-dev-guide/ci/date-check/Cargo.toml")
- {
+ if path.components().any(|c| c.as_os_str() == "library") {
let has = contents.lines().any(is_edition_2018);
if !has {
tidy_error!(
&src_path.join("test/ui"),
&src_path.join("test/ui-fulldeps"),
&src_path.join("test/rustdoc-ui"),
+ &src_path.join("test/rustdoc"),
],
&mut |path| super::filter_dirs(path),
&mut |entry, contents| {
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 1331;
-const ISSUES_ENTRY_LIMIT: usize = 2488;
+const ROOT_ENTRY_LIMIT: usize = 1275;
+const ISSUES_ENTRY_LIMIT: usize = 2310;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
allow-unauthenticated = [
"C-*", "A-*", "E-*", "NLL-*", "O-*", "S-*", "T-*", "WG-*", "F-*",
"D-*",
+ "needs-fcp",
+ "relnotes",
"requires-nightly",
"regression-*",
"perf-*",