- name: mingw-check
os: ubuntu-latest-xl
env: {}
- - name: x86_64-gnu-llvm-10
+ - name: x86_64-gnu-llvm-12
os: ubuntu-latest-xl
env: {}
- name: x86_64-gnu-tools
- name: x86_64-gnu-distcheck
os: ubuntu-latest-xl
env: {}
- - name: x86_64-gnu-llvm-10
+ - name: x86_64-gnu-llvm-12
env:
RUST_BACKTRACE: 1
os: ubuntu-latest-xl
os: ubuntu-latest-xl
- name: dist-x86_64-apple
env:
- SCRIPT: "./x.py dist"
+ 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
+ NO_OVERFLOW_CHECKS: 1
DIST_REQUIRE_ALL_TOOLS: 1
os: macos-latest
- name: dist-x86_64-apple-alt
MACOSX_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
os: macos-latest
- name: x86_64-apple
env:
MACOSX_STD_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
os: macos-latest
- name: dist-aarch64-apple
env:
MACOSX_STD_DEPLOYMENT_TARGET: 11.0
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
DIST_REQUIRE_ALL_TOOLS: 1
JEMALLOC_SYS_WITH_LG_PAGE: 14
os: macos-latest
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>
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da"
+[[package]]
+name = "camino"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "cargo"
-version = "0.58.0"
+version = "0.59.0"
dependencies = [
"anyhow",
"atty",
"bytesize",
- "cargo-platform",
+ "cargo-platform 0.1.2",
"cargo-test-macro",
"cargo-test-support",
"cargo-util",
"serde",
]
+[[package]]
+name = "cargo-platform"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "cargo-test-macro"
version = "0.1.0"
[[package]]
name = "cargo_metadata"
-version = "0.8.2"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426"
+checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345"
dependencies = [
- "semver 0.9.0",
+ "semver 0.11.0",
"serde",
- "serde_derive",
"serde_json",
]
[[package]]
name = "cargo_metadata"
-version = "0.12.0"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345"
+checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a"
dependencies = [
- "semver 0.11.0",
+ "camino",
+ "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 1.0.3",
"serde",
"serde_json",
]
[[package]]
name = "clippy"
-version = "0.1.57"
+version = "0.1.58"
dependencies = [
"cargo_metadata 0.12.0",
"clippy_lints",
dependencies = [
"bytecount",
"clap",
+ "indoc",
"itertools 0.10.1",
"opener",
"regex",
[[package]]
name = "clippy_lints"
-version = "0.1.57"
+version = "0.1.58"
dependencies = [
"cargo_metadata 0.12.0",
"clippy_utils",
[[package]]
name = "clippy_utils"
-version = "0.1.57"
+version = "0.1.58"
dependencies = [
"if_chain",
"rustc-semver",
[[package]]
name = "env_logger"
-version = "0.6.2"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
+checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime 1.3.0",
[[package]]
name = "env_logger"
-version = "0.7.1"
+version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
+checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
dependencies = [
"atty",
- "humantime 1.3.0",
+ "humantime 2.0.1",
"log",
"regex",
"termcolor",
"serde",
]
+[[package]]
+name = "indoc"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136"
+dependencies = [
+ "unindent",
+]
+
[[package]]
name = "installer"
version = "0.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b141fdc7836c525d4d594027d318c84161ca17aaf8113ab1f81ab93ae897485"
-[[package]]
-name = "itertools"
-version = "0.8.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"
-dependencies = [
- "either",
-]
-
[[package]]
name = "itertools"
version = "0.9.0"
[[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",
]
"itertools 0.9.0",
"minifier",
"pulldown-cmark 0.8.0",
+ "rayon",
"regex",
- "rustc-rayon",
"rustdoc-json-types",
"serde",
"serde_json",
[[package]]
name = "rustfmt-nightly"
-version = "1.4.37"
+version = "1.4.38"
dependencies = [
"annotate-snippets",
"anyhow",
"bytecount",
- "cargo_metadata 0.8.2",
+ "cargo_metadata 0.14.0",
"derive-new",
"diff",
"dirs",
- "env_logger 0.6.2",
+ "env_logger 0.8.4",
"getopts",
"ignore",
- "itertools 0.8.2",
+ "itertools 0.9.0",
"lazy_static",
"log",
"regex",
"libc",
]
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-dependencies = [
- "semver-parser 0.7.0",
- "serde",
-]
-
[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
- "semver-parser 0.10.2",
+ "semver-parser",
"serde",
]
"serde",
]
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
[[package]]
name = "semver-parser"
version = "0.10.2"
"diff",
]
+[[package]]
+name = "unindent"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
+
[[package]]
name = "unstable-book-gen"
version = "0.1.0"
# per-crate configuration isn't specifiable in the environment.
codegen-units = 10000
+[profile.release.package.rustc-rayon-core]
+# The rustc fork of Rayon has deadlock detection code which intermittently
+# causes overflows in the CI (see https://github.com/rust-lang/rust/issues/90227)
+# so we turn overflow checks off for now.
+# FIXME: This workaround should be removed once #90227 is fixed.
+overflow-checks = false
+
# These dependencies of the standard library implement symbolication for
# backtraces on most platforms. Their debuginfo causes both linking to be slower
# (more data to chew through) and binaries to be larger without really all that
/// Mutable token visiting only exists for the `macro_rules` token marker and should not be
/// used otherwise. Token visitor would be entirely separate from the regular visitor if
/// the marker didn't have to visit AST fragments in nonterminal tokens.
- fn token_visiting_enabled(&self) -> bool {
- false
- }
+ const VISIT_TOKENS: bool = false;
// Methods in this trait have one of three forms:
//
}
MacArgs::Eq(eq_span, token) => {
vis.visit_span(eq_span);
- if vis.token_visiting_enabled() {
+ if T::VISIT_TOKENS {
visit_token(token, vis);
} else {
// The value in `#[key = VALUE]` must be visited as an expression for backward
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
pub fn visit_tts<T: MutVisitor>(TokenStream(tts): &mut TokenStream, vis: &mut T) {
- if vis.token_visiting_enabled() && !tts.is_empty() {
+ if T::VISIT_TOKENS && !tts.is_empty() {
let tts = Lrc::make_mut(tts);
visit_vec(tts, |(tree, _is_joint)| visit_tt(tree, vis));
}
AttrAnnotatedTokenStream(tts): &mut AttrAnnotatedTokenStream,
vis: &mut T,
) {
- if vis.token_visiting_enabled() && !tts.is_empty() {
+ if T::VISIT_TOKENS && !tts.is_empty() {
let tts = Lrc::make_mut(tts);
visit_vec(tts, |(tree, _is_joint)| visit_attr_annotated_tt(tree, vis));
}
}
pub fn visit_lazy_tts_opt_mut<T: MutVisitor>(lazy_tts: Option<&mut LazyTokenStream>, vis: &mut T) {
- if vis.token_visiting_enabled() {
+ if T::VISIT_TOKENS {
if let Some(lazy_tts) = lazy_tts {
let mut tts = lazy_tts.create_token_stream();
visit_attr_annotated_tts(&mut tts, vis);
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 => {
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")
// 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",
body: &Block,
opt_label: Option<Label>,
) -> hir::Expr<'hir> {
- let orig_head_span = head.span;
// expand <head>
- let mut head = self.lower_expr_mut(head);
- let desugared_span = self.mark_span_with_reason(
- DesugaringKind::ForLoop(ForLoopLoc::Head),
- orig_head_span,
- None,
- );
- head.span = self.lower_span(desugared_span);
+ let head = self.lower_expr_mut(head);
+ let desugared_span =
+ self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), head.span, None);
+ let e_span = self.lower_span(e.span);
let iter = Ident::with_dummy_span(sym::iter);
// `::std::option::Option::Some(val) => __next = val`
let pat_arm = {
let val_ident = Ident::with_dummy_span(sym::val);
- let (val_pat, val_pat_hid) = self.pat_ident(pat.span, val_ident);
- let val_expr = self.expr_ident(pat.span, val_ident, val_pat_hid);
- let next_expr = self.expr_ident(pat.span, next_ident, next_pat_hid);
+ let pat_span = self.lower_span(pat.span);
+ let (val_pat, val_pat_hid) = self.pat_ident(pat_span, val_ident);
+ let val_expr = self.expr_ident(pat_span, val_ident, val_pat_hid);
+ let next_expr = self.expr_ident(pat_span, next_ident, next_pat_hid);
let assign = self.arena.alloc(self.expr(
- pat.span,
- hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat.span)),
+ pat_span,
+ hir::ExprKind::Assign(next_expr, val_expr, self.lower_span(pat_span)),
ThinVec::new(),
));
- let some_pat = self.pat_some(pat.span, val_pat);
+ let some_pat = self.pat_some(pat_span, val_pat);
self.arm(some_pat, assign)
};
// `::std::option::Option::None => break`
let break_arm = {
let break_expr =
- self.with_loop_scope(e.id, |this| this.expr_break_alloc(e.span, ThinVec::new()));
- let pat = self.pat_none(e.span);
+ self.with_loop_scope(e.id, |this| this.expr_break_alloc(e_span, ThinVec::new()));
+ let pat = self.pat_none(e_span);
self.arm(pat, break_expr)
};
let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body, false));
let body_expr = self.expr_block(body_block, ThinVec::new());
- let body_stmt = self.stmt_expr(body.span, body_expr);
+ let body_stmt = self.stmt_expr(body_block.span, body_expr);
let loop_block = self.block_all(
- e.span,
+ e_span,
arena_vec![self; next_let, match_stmt, pat_let, body_stmt],
None,
);
loop_block,
self.lower_label(opt_label),
hir::LoopSource::ForLoop,
- self.lower_span(e.span.with_hi(orig_head_span.hi())),
+ self.lower_span(e_span.with_hi(head.span.hi())),
);
let loop_expr = self.arena.alloc(hir::Expr {
hir_id: self.lower_node_id(e.id),
let into_iter_span = self.mark_span_with_reason(
DesugaringKind::ForLoop(ForLoopLoc::IntoIter),
- orig_head_span,
+ head.span,
None,
);
// #82462: to correctly diagnose borrow errors, the block that contains
// the iter expr needs to have a span that covers the loop body.
let desugared_full_span =
- self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e.span, None);
+ self.mark_span_with_reason(DesugaringKind::ForLoop(ForLoopLoc::Head), e_span, None);
let match_expr = self.arena.alloc(self.expr_match(
desugared_full_span,
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);
}
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
}
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();
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> },
}
};
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
-use rustc_span::source_map::DesugaringKind;
use rustc_span::symbol::sym;
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtExt;
place_name, partially_str, loop_message
),
);
+ let sess = self.infcx.tcx.sess;
+ let ty = used_place.ty(self.body, self.infcx.tcx).ty;
+ // If we have a `&mut` ref, we need to reborrow.
+ if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
+ // If we are in a loop this will be suggested later.
+ if !is_loop_move {
+ err.span_suggestion_verbose(
+ move_span.shrink_to_lo(),
+ &format!(
+ "consider creating a fresh reborrow of {} here",
+ self.describe_place(moved_place.as_ref())
+ .map(|n| format!("`{}`", n))
+ .unwrap_or_else(
+ || "the mutable reference".to_string()
+ ),
+ ),
+ "&mut *".to_string(),
+ Applicability::MachineApplicable,
+ );
+ }
+ } else if let Ok(snippet) =
+ sess.source_map().span_to_snippet(move_span)
+ {
+ err.span_suggestion(
+ move_span,
+ "consider borrowing to avoid moving into the for loop",
+ format!("&{}", snippet),
+ Applicability::MaybeIncorrect,
+ );
+ }
} else {
err.span_label(
fn_call_span,
in_pattern = true;
}
}
-
- if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() {
- let sess = self.infcx.tcx.sess;
- let ty = used_place.ty(self.body, self.infcx.tcx).ty;
- // If we have a `&mut` ref, we need to reborrow.
- if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() {
- // If we are in a loop this will be suggested later.
- if !is_loop_move {
- err.span_suggestion_verbose(
- move_span.shrink_to_lo(),
- &format!(
- "consider creating a fresh reborrow of {} here",
- self.describe_place(moved_place.as_ref())
- .map(|n| format!("`{}`", n))
- .unwrap_or_else(|| "the mutable reference".to_string()),
- ),
- "&mut *".to_string(),
- Applicability::MachineApplicable,
- );
- }
- } else if let Ok(snippet) = sess.source_map().span_to_snippet(move_span) {
- err.span_suggestion(
- move_span,
- "consider borrowing to avoid moving into the for loop",
- format!("&{}", snippet),
- Applicability::MaybeIncorrect,
- );
- }
- }
}
use_spans.var_span_label_path_only(
use rustc_mir_dataflow::move_paths::{
IllegalMoveOrigin, IllegalMoveOriginKind, LookupResult, MoveError, MovePathIndex,
};
-use rustc_span::source_map::DesugaringKind;
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
-use crate::diagnostics::UseSpans;
+use crate::diagnostics::{FnSelfUseKind, UseSpans};
use crate::prefixes::PrefixSet;
use crate::MirBorrowckCtxt;
| ty::Opaque(def_id, _) => def_id,
_ => return err,
};
- let is_option = self.infcx.tcx.is_diagnostic_item(sym::Option, def_id);
- let is_result = self.infcx.tcx.is_diagnostic_item(sym::Result, def_id);
- if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) {
+ let diag_name = self.infcx.tcx.get_diagnostic_name(def_id);
+ if matches!(diag_name, Some(sym::Option | sym::Result))
+ && use_spans.map_or(true, |v| !v.for_closure())
+ {
err.span_suggestion_verbose(
span.shrink_to_hi(),
- &format!(
- "consider borrowing the `{}`'s content",
- if is_option { "Option" } else { "Result" }
- ),
+ &format!("consider borrowing the `{}`'s content", diag_name.unwrap()),
".as_ref()".to_string(),
Applicability::MaybeIncorrect,
);
- } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) {
+ } else if let Some(UseSpans::FnSelfUse {
+ kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. },
+ ..
+ }) = use_spans
+ {
let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) {
Some(def_id) => self.infcx.tcx.infer_ctxt().enter(|infcx| {
type_known_to_meet_bound_modulo_regions(
#![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)]
use self::path_utils::*;
-mod borrow_set;
+pub mod borrow_set;
mod borrowck_errors;
mod constraint_generation;
mod constraints;
Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
}))),
locations,
category,
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;
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 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,
}
}
+ 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())
}
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);
}
}
+ 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])
}
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 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");
}
}
// Ref:
// - https://github.com/rust-lang/rust/issues/85351
// - https://reviews.llvm.org/D103167
- let llvm_version = llvm_util::get_version();
- if llvm_version >= (11, 0, 0) && llvm_version < (13, 0, 0) {
+ if llvm_util::get_version() < (13, 0, 0) {
add("-enable-machine-outliner=never", false);
}
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;
}
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.clone());
+
+ // 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.clone());
+ }
}
/// Produces, for each argument, a `Value` pointing at the
("crypto", Some(sym::arm_target_feature)),
("aes", Some(sym::arm_target_feature)),
("sha2", Some(sym::arm_target_feature)),
+ ("i8mm", Some(sym::arm_target_feature)),
("v5te", Some(sym::arm_target_feature)),
("v6", Some(sym::arm_target_feature)),
("v6k", Some(sym::arm_target_feature)),
// 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)),
// FEAT_F64MM
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>,
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;
&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)?))
line: u32,
col: u32,
) -> MPlaceTy<'tcx, M::PointerTag> {
- let file =
- self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not);
- let line = Scalar::from_u32(line);
- let col = Scalar::from_u32(col);
+ let loc_details = &self.tcx.sess.opts.debugging_opts.location_detail;
+ let file = if loc_details.file {
+ self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not)
+ } else {
+ // FIXME: This creates a new allocation each time. It might be preferable to
+ // perform this allocation only once, and re-use the `MPlaceTy`.
+ // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398
+ self.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not)
+ };
+ let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) };
+ let col = if loc_details.column { Scalar::from_u32(col) } else { Scalar::from_u32(0) };
// Allocate memory for `CallerLocation` struct.
let loc_ty = self
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(
.into_results_cursor(&ccx.body);
cursor.seek_after_primary_effect(return_loc);
- cursor.contains(RETURN_PLACE)
+ cursor.get().contains(RETURN_PLACE)
}
};
Binder::dummy(TraitPredicate {
trait_ref,
constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
}),
);
}
// 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),
}
}
}
}
-/// 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,
/// Whether this `Qualif` is cleared when a local is moved from.
const IS_CLEARED_ON_MOVE: bool = false;
+ /// Whether this `Qualif` might be evaluated after the promotion and can encounter a promoted.
+ const ALLOW_PROMOTED: bool = false;
+
/// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`.
fn in_qualifs(qualifs: &ConstQualifs) -> bool;
impl Qualif for NeedsNonConstDrop {
const ANALYSIS_NAME: &'static str = "flow_needs_nonconst_drop";
const IS_CLEARED_ON_MOVE: bool = true;
+ const ALLOW_PROMOTED: bool = true;
fn in_qualifs(qualifs: &ConstQualifs) -> bool {
qualifs.needs_non_const_drop
ty::Binder::dummy(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::ConstIfConst,
+ polarity: ty::ImplPolarity::Positive,
}),
);
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...
// Check the qualifs of the value of `const` items.
if let Some(ct) = constant.literal.const_for_ty() {
if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) = ct.val {
- assert!(promoted.is_none());
+ // Use qualifs of the type for the promoted. Promoteds in MIR body should be possible
+ // only for `NeedsNonConstDrop` with precise drop checking. This is the only const
+ // check performed after the promotion. Verify that with an assertion.
+ assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
// Don't peek inside trait associated constants.
- if cx.tcx.trait_of_item(def.did).is_none() {
+ if promoted.is_none() && cx.tcx.trait_of_item(def.did).is_none() {
let qualifs = if let Some((did, param_did)) = def.as_const_arg() {
cx.tcx.at(constant.span).mir_const_qualif_const_arg((did, param_did))
} else {
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{self, BasicBlock, Local, Location};
+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 {
+ match mt {
+ mir::Mutability::Mut => true,
+ mir::Mutability::Not => self.shared_borrow_allows_mutation(place),
+ }
+ }
+
+ 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)
+ }
+ }
+ }
+
+ 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.state.qualif.remove(local);
+ self.state.borrow.remove(local);
+ }
+ _ => self.super_statement(statement, location),
+ }
+ }
+
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
// The effect of assignment to the return place in `TerminatorKind::Call` is not applied
// here; that occurs in `apply_call_return_effect`.
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 {
#![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)]
+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;
}
}
+impl<CTX> HashStable<CTX> for [u8] {
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ self.len().hash_stable(ctx, hasher);
+ hasher.write(self);
+ }
+}
+
impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> {
#[inline]
fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
-An underscore `_` character has been used as the identifier for a lifetime.
+`'_` lifetime name or `&T` without an explicit lifetime name has been used
+on illegal place.
Erroneous code example:
```compile_fail,E0106,E0637
-fn longest<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
- //^^ `'_` is a reserved lifetime name
+fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+ //^^ `'_` is a reserved lifetime name
if str1.len() > str2.len() {
str1
} else {
str2
}
}
+
+fn and_without_explicit_lifetime<T>()
+where
+ T: Into<&u32>,
+ //^ `&` without an explicit lifetime name
+{
+}
```
-`'_`, cannot be used as a lifetime identifier because it is a reserved for the
-anonymous lifetime. To fix this, use a lowercase letter such as 'a, or a series
-of lowercase letters such as `'foo`. For more information, see [the
-book][bk-no]. For more information on using the anonymous lifetime in rust
-nightly, see [the nightly book][bk-al].
+First, `'_` cannot be used as a lifetime identifier in some places
+because it is a reserved for the anonymous lifetime. Second, `&T`
+without an explicit lifetime name cannot also be used in some places.
+To fix them, use a lowercase letter such as `'a`, or a series
+of lowercase letters such as `'foo`. For more information about lifetime
+identifier, see [the book][bk-no]. For more information on using
+the anonymous lifetime in Rust 2018, see [the Rust 2018 blog post][blog-al].
Corrected example:
```
-fn longest<'a>(str1: &'a str, str2: &'a str) -> &'a str {
+fn underscore_lifetime<'a>(str1: &'a str, str2: &'a str) -> &'a str {
if str1.len() > str2.len() {
str1
} else {
str2
}
}
+
+fn and_without_explicit_lifetime<'foo, T>()
+where
+ T: Into<&'foo u32>,
+{
+}
```
[bk-no]: https://doc.rust-lang.org/book/appendix-02-operators.html#non-operator-symbols
-[bk-al]: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/ownership-and-lifetimes/the-anonymous-lifetime.html
+[blog-al]: https://blog.rust-lang.org/2018/12/06/Rust-1.31-and-rust-2018.html#more-lifetime-elision-rules
suggestions: impl Iterator<Item = String>,
applicability: Applicability,
) -> &mut Self {
+ let mut suggestions: Vec<_> = suggestions.collect();
+ suggestions.sort();
+ let substitutions = suggestions
+ .into_iter()
+ .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
+ .collect();
self.suggestions.push(CodeSuggestion {
- substitutions: suggestions
- .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
- .collect(),
+ substitutions,
msg: msg.to_owned(),
style: SuggestionStyle::ShowCode,
applicability,
use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
use crate::styled_buffer::StyledBuffer;
use crate::{
- CodeSuggestion, Diagnostic, DiagnosticId, Level, SubDiagnostic, SubstitutionHighlight,
+ CodeSuggestion, Diagnostic, DiagnosticId, Handler, Level, SubDiagnostic, SubstitutionHighlight,
SuggestionStyle,
};
}
}
-/// An emitter that does nothing when emitting a diagnostic.
-pub struct SilentEmitter;
+/// An emitter that does nothing when emitting a non-fatal diagnostic.
+/// Fatal diagnostics are forwarded to `fatal_handler` to avoid silent
+/// failures of rustc, as witnessed e.g. in issue #89358.
+pub struct SilentEmitter {
+ pub fatal_handler: Handler,
+ pub fatal_note: Option<String>,
+}
impl Emitter for SilentEmitter {
fn source_map(&self) -> Option<&Lrc<SourceMap>> {
None
}
- fn emit_diagnostic(&mut self, _: &Diagnostic) {}
+ fn emit_diagnostic(&mut self, d: &Diagnostic) {
+ if d.level == Level::Fatal {
+ let mut d = d.clone();
+ if let Some(ref note) = self.fatal_note {
+ d.note(note);
+ }
+ self.fatal_handler.emit_diagnostic(&d);
+ }
+ }
}
/// Maximum number of lines we will print for a multiline suggestion; arbitrary.
struct Marker(LocalExpnId, Transparency);
impl MutVisitor for Marker {
- fn token_visiting_enabled(&self) -> bool {
- true
- }
+ const VISIT_TOKENS: bool = true;
fn visit_span(&mut self, span: &mut Span) {
*span = span.apply_mark(self.0.to_expn_id(), self.1)
struct ToZzIdentMutVisitor;
impl MutVisitor for ToZzIdentMutVisitor {
- fn token_visiting_enabled(&self) -> bool {
- true
- }
+ const VISIT_TOKENS: bool = true;
+
fn visit_ident(&mut self, ident: &mut Ident) {
*ident = Ident::from_str("zz");
}
/// Allows using the `non_exhaustive_omitted_patterns` lint.
(active, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554), None),
+ /// Allows creation of instances of a struct by moving fields that have
+ /// not changed from prior instances of the same struct (RFC #2528)
+ (incomplete, type_changing_struct_update, "1.58.0", Some(86555), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
rustc_attr!(TEST, rustc_outlives, Normal, template!(Word)),
rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word)),
rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word)),
+ rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word)),
rustc_attr!(TEST, rustc_variance, Normal, template!(Word)),
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
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 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.
#[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)
}
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))
}
}
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
-use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::print::RegionHighlightMode;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+
use rustc_span::{MultiSpan, Span, Symbol};
+use std::ops::ControlFlow;
+
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`.
pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> {
.tcx()
.sess
.struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
+
+ // Mark all unnamed regions in the type with a number.
+ // This diagnostic is called in response to lifetime errors, so be informative.
+ struct HighlightBuilder<'tcx> {
+ highlight: RegionHighlightMode,
+ tcx: TyCtxt<'tcx>,
+ counter: usize,
+ }
+
+ impl HighlightBuilder<'tcx> {
+ fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode {
+ let mut builder =
+ HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1, tcx };
+ builder.visit_ty(ty);
+ builder.highlight
+ }
+ }
+
+ impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder<'tcx> {
+ fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
+ Some(self.tcx)
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+ if !r.has_name() && self.counter <= 3 {
+ self.highlight.highlighting_region(r, self.counter);
+ self.counter += 1;
+ }
+ r.super_visit_with(self)
+ }
+ }
+
+ let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
+ let expected = self
+ .infcx
+ .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
+ .name;
+ let found_highlight = HighlightBuilder::build(self.tcx(), found);
+ let found =
+ self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
+
err.span_label(sp, &format!("found `{}`", found));
err.span_label(trait_sp, &format!("expected `{}`", expected));
);
}
- if let Some((expected, found)) =
- self.infcx.expected_found_str_ty(ExpectedFound { expected, found })
- {
- // Highlighted the differences when showing the "expected/found" note.
- err.note_expected_found(&"", expected, &"", found);
- } else {
- // This fallback shouldn't be necessary, but let's keep it in just in case.
- err.note(&format!("expected `{}`\n found `{}`", expected, found));
- }
+ err.note(&format!("expected `{}`\n found `{}`", expected, found));
+
err.span_help(
type_param_span,
"the lifetime requirements from the `impl` do not correspond to the requirements in \
+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
+}
use rustc_hir as hir;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Const, Ty};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt};
use rustc_span::Span;
pub use self::FulfillmentErrorCode::*;
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
+impl PredicateObligation<'tcx> {
+ /// Flips the polarity of the inner predicate.
+ ///
+ /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
+ pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<PredicateObligation<'tcx>> {
+ Some(PredicateObligation {
+ cause: self.cause.clone(),
+ param_env: self.param_env,
+ predicate: self.predicate.flip_polarity(tcx)?,
+ recursion_depth: self.recursion_depth,
+ })
+ }
+}
+
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(PredicateObligation<'_>, 32);
}
impl<'tcx> TraitObligation<'tcx> {
+ pub fn polarity(&self) -> ty::ImplPolarity {
+ self.predicate.skip_binder().polarity
+ }
+
pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
self.predicate.map_bound(|p| p.self_ty())
}
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 {
let cfg = cfgspecs
.into_iter()
.map(|s| {
- let sess = ParseSess::with_silent_emitter();
+ let sess = ParseSess::with_silent_emitter(Some(format!(
+ "this error occurred on the command line: `--cfg={}`",
+ s
+ )));
let filename = FileName::cfg_spec_source_code(&s);
let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());
///
/// 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:
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};
*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 {
use rustc_session::config::InstrumentCoverage;
use rustc_session::config::Strip;
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
-use rustc_session::config::{rustc_optgroups, ErrorOutputType, ExternLocation, Options, Passes};
+use rustc_session::config::{
+ rustc_optgroups, ErrorOutputType, ExternLocation, LocationDetail, Options, Passes,
+};
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
use rustc_session::config::{
Externs, OutputType, OutputTypes, SymbolManglingVersion, WasiExecModel,
tracked!(instrument_mcount, true);
tracked!(link_only, true);
tracked!(llvm_plugins, vec![String::from("plugin_name")]);
+ tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(mir_emit_retag, true);
tracked!(mir_opt_level, Some(4));
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);
Applicability::MachineApplicable,
);
if self.for_expr_span == expr.span {
- let expr_span = expr.span.ctxt().outer_expn_data().call_site;
diag.span_suggestion(
- receiver_arg.span.shrink_to_hi().to(expr_span.shrink_to_hi()),
+ receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
"or remove `.into_iter()` to iterate by value",
String::new(),
Applicability::MaybeIncorrect,
/// [issue #50504]: https://github.com/rust-lang/rust/issues/50504
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
- Warn,
+ Deny,
"detects proc macro derives using inaccessible names from parent modules",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
/// [issue #83125]: https://github.com/rust-lang/rust/issues/83125
/// [future-incompatible]: ../index.md#future-incompatible-lints
pub PROC_MACRO_BACK_COMPAT,
- Warn,
+ Deny,
"detects usage of old versions of certain proc-macro crates",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #83125 <https://github.com/rust-lang/rust/issues/83125>",
extern "C" void LLVMRustCoverageWriteFuncSectionNameToString(LLVMModuleRef M,
RustStringRef Str) {
-#if LLVM_VERSION_GE(11, 0)
WriteSectionNameToString(M, IPSK_covfun, Str);
-// else do nothing; the `Version` check will abort codegen on the Rust side
-#endif
}
extern "C" void LLVMRustCoverageWriteMappingVarNameToString(RustStringRef Str) {
}
extern "C" uint32_t LLVMRustCoverageMappingVersion() {
-#if LLVM_VERSION_GE(11, 0)
return coverage::CovMapVersion::Version4;
-#else
- return coverage::CovMapVersion::Version3;
-#endif
}
DEFINE_STDCXX_CONVERSION_FUNCTIONS(Pass, LLVMPassRef)
DEFINE_STDCXX_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
-#if LLVM_VERSION_LT(11, 0)
-DEFINE_STDCXX_CONVERSION_FUNCTIONS(PassManagerBuilder,
- LLVMPassManagerBuilderRef)
-#endif
extern "C" void LLVMInitializePasses() {
PassRegistry &Registry = *PassRegistry::getPassRegistry();
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;
PassInstrumentationCallbacks& PIC, void* LlvmSelfProfiler,
LLVMRustSelfProfileBeforePassCallback BeforePassCallback,
LLVMRustSelfProfileAfterPassCallback AfterPassCallback) {
-#if LLVM_VERSION_GE(12, 0)
PIC.registerBeforeNonSkippedPassCallback([LlvmSelfProfiler, BeforePassCallback](
StringRef Pass, llvm::Any Ir) {
std::string PassName = Pass.str();
[LlvmSelfProfiler, AfterPassCallback](StringRef Pass, const PreservedAnalyses &Preserved) {
AfterPassCallback(LlvmSelfProfiler);
});
-#else
- PIC.registerBeforePassCallback([LlvmSelfProfiler, BeforePassCallback](
- StringRef Pass, llvm::Any Ir) {
- std::string PassName = Pass.str();
- std::string IrName = LLVMRustwrappedIrGetName(Ir);
- BeforePassCallback(LlvmSelfProfiler, PassName.c_str(), IrName.c_str());
- return true;
- });
-
- PIC.registerAfterPassCallback(
- [LlvmSelfProfiler, AfterPassCallback](StringRef Pass, llvm::Any Ir) {
- AfterPassCallback(LlvmSelfProfiler);
- });
-
- PIC.registerAfterPassInvalidatedCallback(
- [LlvmSelfProfiler, AfterPassCallback](StringRef Pass) {
- AfterPassCallback(LlvmSelfProfiler);
- });
-#endif
PIC.registerBeforeAnalysisCallback([LlvmSelfProfiler, BeforePassCallback](
StringRef Pass, llvm::Any Ir) {
PTO.LoopInterleaving = UnrollLoops;
PTO.LoopVectorization = LoopVectorize;
PTO.SLPVectorization = SLPVectorize;
-#if LLVM_VERSION_GE(12, 0)
PTO.MergeFunctions = MergeFunctions;
-#else
- // MergeFunctions is not supported by NewPM in older LLVM versions.
- (void) MergeFunctions;
-#endif
// FIXME: We may want to expose this as an option.
bool DebugPassManager = false;
PassInstrumentationCallbacks PIC;
-#if LLVM_VERSION_GE(12, 0)
StandardInstrumentations SI(DebugPassManager);
-#else
- StandardInstrumentations SI;
-#endif
SI.registerCallbacks(PIC);
if (LlvmSelfProfiler){
PGOOptions::NoCSAction, DebugInfoForProfiling);
}
-#if LLVM_VERSION_GE(12, 0) && !LLVM_VERSION_GE(13,0)
- PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC);
-#else
- PassBuilder PB(TM, PTO, PGOOpt, &PIC);
-#endif
-
#if LLVM_VERSION_GE(13, 0)
+ PassBuilder PB(TM, PTO, PGOOpt, &PIC);
LoopAnalysisManager LAM;
FunctionAnalysisManager FAM;
CGSCCAnalysisManager CGAM;
ModuleAnalysisManager MAM;
#else
+ PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC);
LoopAnalysisManager LAM(DebugPassManager);
FunctionAnalysisManager FAM(DebugPassManager);
CGSCCAnalysisManager CGAM(DebugPassManager);
// PassBuilder does not create a pipeline.
std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
PipelineStartEPCallbacks;
-#if LLVM_VERSION_GE(11, 0)
std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>>
OptimizerLastEPCallbacks;
-#else
- std::vector<std::function<void(FunctionPassManager &, OptimizationLevel)>>
- OptimizerLastEPCallbacks;
-#endif
if (VerifyIR) {
PipelineStartEPCallbacks.push_back(
SanitizerOptions->SanitizeMemoryTrackOrigins,
SanitizerOptions->SanitizeMemoryRecover,
/*CompileKernel=*/false);
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[Options](ModulePassManager &MPM, OptimizationLevel Level) {
#if LLVM_VERSION_GE(14, 0)
MPM.addPass(createModuleToFunctionPassAdaptor(MemorySanitizerPass(Options)));
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [Options](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(MemorySanitizerPass(Options));
- }
- );
- OptimizerLastEPCallbacks.push_back(
- [Options](FunctionPassManager &FPM, OptimizationLevel Level) {
- FPM.addPass(MemorySanitizerPass(Options));
- }
- );
-#endif
}
if (SanitizerOptions->SanitizeThread) {
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[](ModulePassManager &MPM, OptimizationLevel Level) {
#if LLVM_VERSION_GE(14, 0)
MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass()));
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(ThreadSanitizerPass());
- }
- );
- OptimizerLastEPCallbacks.push_back(
- [](FunctionPassManager &FPM, OptimizationLevel Level) {
- FPM.addPass(ThreadSanitizerPass());
- }
- );
-#endif
}
if (SanitizerOptions->SanitizeAddress) {
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
#endif
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [&](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(RequireAnalysisPass<ASanGlobalsMetadataAnalysis, Module>());
- }
- );
- OptimizerLastEPCallbacks.push_back(
- [SanitizerOptions](FunctionPassManager &FPM, OptimizationLevel Level) {
- FPM.addPass(AddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover,
- /*UseAfterScope=*/true));
- }
- );
- PipelineStartEPCallbacks.push_back(
- [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(ModuleAddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeAddressRecover));
- }
- );
-#endif
}
if (SanitizerOptions->SanitizeHWAddress) {
-#if LLVM_VERSION_GE(11, 0)
OptimizerLastEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
#if LLVM_VERSION_GE(14, 0)
#endif
}
);
-#else
- PipelineStartEPCallbacks.push_back(
- [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) {
- MPM.addPass(HWAddressSanitizerPass(
- /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover));
- }
- );
-#endif
}
}
// At the same time, the LTO pipelines do support O0 and using them is required.
bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO;
if (OptLevel == OptimizationLevel::O0 && !IsLTO) {
-#if LLVM_VERSION_GE(12, 0)
for (const auto &C : PipelineStartEPCallbacks)
PB.registerPipelineStartEPCallback(C);
for (const auto &C : OptimizerLastEPCallbacks)
// Pass false as we manually schedule ThinLTOBufferPasses below.
MPM = PB.buildO0DefaultPipeline(OptLevel, /* PreLinkLTO */ false);
-#else
- for (const auto &C : PipelineStartEPCallbacks)
- C(MPM, OptLevel);
-
-# if LLVM_VERSION_GE(11, 0)
- for (const auto &C : OptimizerLastEPCallbacks)
- C(MPM, OptLevel);
-# else
- if (!OptimizerLastEPCallbacks.empty()) {
- FunctionPassManager FPM(DebugPassManager);
- for (const auto &C : OptimizerLastEPCallbacks)
- C(FPM, OptLevel);
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
- }
-# endif
-
- MPM.addPass(AlwaysInlinerPass(EmitLifetimeMarkers));
-
- if (PGOOpt) {
- PB.addPGOInstrPassesForO0(
- MPM, DebugPassManager, PGOOpt->Action == PGOOptions::IRInstr,
- /*IsCS=*/false, PGOOpt->ProfileFile, PGOOpt->ProfileRemappingFile);
- }
-#endif
} else {
-#if LLVM_VERSION_GE(12, 0)
for (const auto &C : PipelineStartEPCallbacks)
PB.registerPipelineStartEPCallback(C);
-#else
- for (const auto &C : PipelineStartEPCallbacks)
- PB.registerPipelineStartEPCallback([C, OptLevel](ModulePassManager &MPM) {
- C(MPM, OptLevel);
- });
-#endif
if (OptStage != LLVMRustOptStage::PreLinkThinLTO) {
for (const auto &C : OptimizerLastEPCallbacks)
PB.registerOptimizerLastEPCallback(C);
MPM = PB.buildPerModuleDefaultPipeline(OptLevel, DebugPassManager);
break;
case LLVMRustOptStage::PreLinkThinLTO:
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel);
// The ThinLTOPreLink pipeline already includes ThinLTOBuffer passes. However, callback
// passes may still run afterwards. This means we need to run the buffer passes again.
// before the RequiredLTOPreLinkPasses, in which case we can remove these hacks.
if (OptimizerLastEPCallbacks.empty())
NeedThinLTOBufferPasses = false;
-#else
- MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
-#endif
-#if LLVM_VERSION_GE(11, 0)
for (const auto &C : OptimizerLastEPCallbacks)
C(MPM, OptLevel);
-#else
- if (!OptimizerLastEPCallbacks.empty()) {
- FunctionPassManager FPM(DebugPassManager);
- for (const auto &C : OptimizerLastEPCallbacks)
- C(FPM, OptLevel);
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
- }
-#endif
break;
case LLVMRustOptStage::PreLinkFatLTO:
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel);
NeedThinLTOBufferPasses = false;
-#else
- MPM = PB.buildLTOPreLinkDefaultPipeline(OptLevel, DebugPassManager);
-#endif
break;
case LLVMRustOptStage::ThinLTO:
// FIXME: Does it make sense to pass the ModuleSummaryIndex?
// It only seems to be needed for C++ specific optimizations.
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildThinLTODefaultPipeline(OptLevel, nullptr);
-#else
- MPM = PB.buildThinLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
-#endif
break;
case LLVMRustOptStage::FatLTO:
-#if LLVM_VERSION_GE(12, 0)
MPM = PB.buildLTODefaultPipeline(OptLevel, nullptr);
-#else
- MPM = PB.buildLTODefaultPipeline(OptLevel, DebugPassManager, nullptr);
-#endif
break;
}
}
// `ProcessThinLTOModule` function. Here they're split up into separate steps
// so rustc can save off the intermediate bytecode between each step.
-#if LLVM_VERSION_GE(11, 0)
static bool
clearDSOLocalOnDeclarations(Module &Mod, TargetMachine &TM) {
// When linking an ELF shared object, dso_local should be dropped. We
Mod.getPIELevel() == PIELevel::Default;
return ClearDSOLocalOnDeclarations;
}
-#endif
extern "C" bool
LLVMRustPrepareThinLTORename(const LLVMRustThinLTOData *Data, LLVMModuleRef M,
Module &Mod = *unwrap(M);
TargetMachine &Target = *unwrap(TM);
-#if LLVM_VERSION_GE(11, 0)
bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
bool error = renameModuleForThinLTO(Mod, Data->Index, ClearDSOLocal);
-#else
- bool error = renameModuleForThinLTO(Mod, Data->Index);
-#endif
if (error) {
LLVMRustSetLastError("renameModuleForThinLTO failed");
return MOrErr;
};
-#if LLVM_VERSION_GE(11, 0)
bool ClearDSOLocal = clearDSOLocalOnDeclarations(Mod, Target);
FunctionImporter Importer(Data->Index, Loader, ClearDSOLocal);
-#else
- FunctionImporter Importer(Data->Index, Loader);
-#endif
Expected<bool> Result = Importer.importFunctions(Mod, ImportList);
if (!Result) {
LLVMRustSetLastError(toString(Result.takeError()).c_str());
extern "C" void LLVMRustAddStructRetCallSiteAttr(LLVMValueRef Instr, unsigned Index,
LLVMTypeRef Ty) {
CallBase *Call = unwrap<CallBase>(Instr);
-#if LLVM_VERSION_GE(12, 0)
Attribute Attr = Attribute::getWithStructRetType(Call->getContext(), unwrap(Ty));
-#else
- Attribute Attr = Attribute::get(Call->getContext(), Attribute::StructRet);
-#endif
AddAttribute(Call, Index, Attr);
}
extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index,
LLVMTypeRef Ty) {
Function *F = unwrap<Function>(Fn);
-#if LLVM_VERSION_GE(12, 0)
Attribute Attr = Attribute::getWithStructRetType(F->getContext(), unwrap(Ty));
-#else
- Attribute Attr = Attribute::get(F->getContext(), Attribute::StructRet);
-#endif
AddAttribute(F, Index, Attr);
}
return DIFile::ChecksumKind::CSK_MD5;
case LLVMRustChecksumKind::SHA1:
return DIFile::ChecksumKind::CSK_SHA1;
-#if (LLVM_VERSION_MAJOR >= 11)
case LLVMRustChecksumKind::SHA256:
return DIFile::ChecksumKind::CSK_SHA256;
-#endif
default:
report_fatal_error("bad ChecksumKind.");
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter(
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope,
const char *Name, size_t NameLen, LLVMMetadataRef Ty) {
-#if LLVM_VERSION_GE(11, 0)
bool IsDefault = false; // FIXME: should we ever set this true?
return wrap(Builder->createTemplateTypeParameter(
unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty), IsDefault));
-#else
- return wrap(Builder->createTemplateTypeParameter(
- unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), unwrapDI<DIType>(Ty)));
-#endif
}
extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateNameSpace(
LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
LLVMMetadataRef ScopeRef,
LLVMMetadataRef InlinedAt) {
-#if LLVM_VERSION_GE(12, 0)
MDNode *Scope = unwrapDIPtr<MDNode>(ScopeRef);
DILocation *Loc = DILocation::get(
Scope->getContext(), Line, Column, Scope,
unwrapDIPtr<MDNode>(InlinedAt));
return wrap(Loc);
-#else
- DebugLoc debug_loc = DebugLoc::get(Line, Column, unwrapDIPtr<MDNode>(ScopeRef),
- unwrapDIPtr<MDNode>(InlinedAt));
- return wrap(debug_loc.getAsMDNode());
-#endif
}
extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() {
return LLVMArrayTypeKind;
case Type::PointerTyID:
return LLVMPointerTypeKind;
-#if LLVM_VERSION_GE(11, 0)
case Type::FixedVectorTyID:
return LLVMVectorTypeKind;
-#else
- case Type::VectorTyID:
- return LLVMVectorTypeKind;
-#endif
case Type::X86_MMXTyID:
return LLVMX86_MMXTypeKind;
case Type::TokenTyID:
return LLVMTokenTypeKind;
-#if LLVM_VERSION_GE(11, 0)
case Type::ScalableVectorTyID:
return LLVMScalableVectorTypeKind;
case Type::BFloatTyID:
return LLVMBFloatTypeKind;
-#endif
-#if LLVM_VERSION_GE(12, 0)
case Type::X86_AMXTyID:
return LLVMX86_AMXTypeKind;
-#endif
}
report_fatal_error("Unhandled TypeID.");
}
}
extern "C" LLVMValueRef
LLVMRustBuildVectorReduceFMin(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) {
-#if LLVM_VERSION_GE(12, 0)
Instruction *I = unwrap(B)->CreateFPMinReduce(unwrap(Src));
I->setHasNoNaNs(NoNaN);
return wrap(I);
-#else
- return wrap(unwrap(B)->CreateFPMinReduce(unwrap(Src), NoNaN));
-#endif
}
extern "C" LLVMValueRef
LLVMRustBuildVectorReduceFMax(LLVMBuilderRef B, LLVMValueRef Src, bool NoNaN) {
-#if LLVM_VERSION_GE(12, 0)
Instruction *I = unwrap(B)->CreateFPMaxReduce(unwrap(Src));
I->setHasNoNaNs(NoNaN);
return wrap(I);
-#else
- return wrap(unwrap(B)->CreateFPMaxReduce(unwrap(Src), NoNaN));
-#endif
}
extern "C" LLVMValueRef
Storage(Type),
/// Cache the query to disk if the `Expr` returns true.
- Cache(Option<(IdentOrWild, IdentOrWild)>, Block),
+ Cache(Option<IdentOrWild>, Block),
/// Custom code to load the query from disk.
LoadCached(Ident, Ident, Block),
/// 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 {
let args;
parenthesized!(args in input);
let tcx = args.parse()?;
- args.parse::<Token![,]>()?;
- let value = args.parse()?;
- Some((tcx, value))
+ Some(tcx)
} else {
None
};
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"))
}
storage: Option<Type>,
/// Cache the query to disk if the `Block` returns true.
- cache: Option<(Option<(IdentOrWild, IdentOrWild)>, Block)>,
+ cache: Option<(Option<IdentOrWild>, Block)>,
/// Custom code to load the query from disk.
load_cached: Option<(Ident, Ident, Block)>,
// 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));
}
};
let tcx = args
.as_ref()
.map(|t| {
- let t = &(t.0).0;
- quote! { #t }
- })
- .unwrap_or_else(|| quote! { _ });
- let value = args
- .as_ref()
- .map(|t| {
- let t = &(t.1).0;
+ let t = &t.0;
quote! { #t }
})
.unwrap_or_else(|| quote! { _ });
// 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,
- #value: Option<&Self::Value>
- ) -> 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 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
};
}
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)
}
/// or `typeck` appears in the name.
/// - `foo & nll | bar & typeck` == match if `foo` and `nll` both appear in the name
/// or `typeck` and `bar` both appear in the name.
+#[inline]
pub fn dump_mir<'tcx, F>(
tcx: TyCtxt<'tcx>,
pass_num: Option<&dyn Display>,
/// 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, opt_result) {
- tcx.is_closure(key.to_def_id())
- || opt_result.map_or(false, |r| !r.concrete_opaque_types.is_empty())
- }
+ cache_on_disk_if(tcx) { tcx.is_closure(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" }
#[derive(Clone, Debug, TypeFoldable, Lift)]
pub enum SelectionError<'tcx> {
+ /// The trait is not implemented.
Unimplemented,
+ /// After a closure impl has selected, its "outputs" were evaluated
+ /// (which for closures includes the "input" type params) and they
+ /// didn't resolve. See `confirm_poly_trait_refs` for more.
OutputTypeParameterMismatch(
ty::PolyTraitRef<'tcx>,
ty::PolyTraitRef<'tcx>,
ty::error::TypeError<'tcx>,
),
+ /// The trait pointed by `DefId` is not object safe.
TraitNotObjectSafe(DefId),
+ /// A given constant couldn't be evaluated.
NotConstEvaluatable(NotConstEvaluatable),
+ /// Exceeded the recursion depth during type projection.
Overflow,
+ /// Signaling that an error has already been emitted, to avoid
+ /// multiple errors being shown.
ErrorReporting,
+ /// Multiple applicable `impl`s where found. The `DefId`s correspond to
+ /// all the `impl`s' Items.
+ Ambiguous(Vec<DefId>),
}
/// When performing resolution, it is typically the case that there
use rustc_query_system::cache::Cache;
pub type SelectionCache<'tcx> = Cache<
- ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>,
+ (ty::ConstnessAnd<ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>>, ty::ImplPolarity),
SelectionResult<'tcx, SelectionCandidate<'tcx>>,
>;
-pub type EvaluationCache<'tcx> =
- Cache<ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, EvaluationResult>;
+pub type EvaluationCache<'tcx> = Cache<
+ (ty::ParamEnvAnd<'tcx, ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>>, ty::ImplPolarity),
+ EvaluationResult,
+>;
/// The selection process begins by considering all impls, where
/// clauses, and so forth that might resolve an obligation. Sometimes
/// `false` if there are no *further* obligations.
has_nested: bool,
},
- ParamCandidate(ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>),
+ ParamCandidate((ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>, ty::ImplPolarity)),
ImplCandidate(DefId),
AutoImplCandidate(DefId),
pub enum TypeError<'tcx> {
Mismatch,
ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
+ PolarityMismatch(ExpectedFound<ty::ImplPolarity>),
UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
AbiMismatch(ExpectedFound<abi::Abi>),
Mutability,
ConstnessMismatch(values) => {
write!(f, "expected {} bound, found {} bound", values.expected, values.found)
}
+ PolarityMismatch(values) => {
+ write!(f, "expected {} polarity, found {} polarity", values.expected, values.found)
+ }
UnsafetyMismatch(values) => {
write!(f, "expected {} fn, found {} fn", values.expected, values.found)
}
use self::TypeError::*;
match self {
CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
- | Mismatch | AbiMismatch(_) | FixedArraySize(_) | ArgumentSorts(..) | Sorts(_)
- | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) | TargetFeatureCast(_) => {
- false
- }
+ | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
+ | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
+ | VariadicMismatch(_) | TargetFeatureCast(_) => false,
Mutability
| ArgumentMutability(_)
pub predicates: Vec<Predicate<'tcx>>,
}
-#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
+#[derive(
+ Copy,
+ Clone,
+ PartialEq,
+ Eq,
+ Hash,
+ TyEncodable,
+ TyDecodable,
+ HashStable,
+ Debug,
+ TypeFoldable
+)]
pub enum ImplPolarity {
/// `impl Trait for Type`
Positive,
Reservation,
}
+impl ImplPolarity {
+ /// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`.
+ pub fn flip(&self) -> Option<ImplPolarity> {
+ match self {
+ ImplPolarity::Positive => Some(ImplPolarity::Negative),
+ ImplPolarity::Negative => Some(ImplPolarity::Positive),
+ ImplPolarity::Reservation => None,
+ }
+ }
+}
+
+impl fmt::Display for ImplPolarity {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ Self::Positive => f.write_str("positive"),
+ Self::Negative => f.write_str("negative"),
+ Self::Reservation => f.write_str("reservation"),
+ }
+ }
+}
+
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, TyEncodable, TyDecodable, HashStable)]
pub enum Visibility {
/// Visible everywhere (including in other crates).
pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
self.inner.kind
}
+
+ /// Flips the polarity of a Predicate.
+ ///
+ /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
+ pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> {
+ let kind = self
+ .inner
+ .kind
+ .map_bound(|kind| match kind {
+ PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => {
+ Some(PredicateKind::Trait(TraitPredicate {
+ trait_ref,
+ constness,
+ polarity: polarity.flip()?,
+ }))
+ }
+
+ _ => None,
+ })
+ .transpose()?;
+
+ Some(tcx.mk_predicate(kind))
+ }
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
pub trait_ref: TraitRef<'tcx>,
pub constness: BoundConstness,
+
+ pub polarity: ImplPolarity,
}
pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
self.value
.map_bound(|trait_ref| {
- PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: self.constness })
+ PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ constness: self.constness,
+ polarity: ty::ImplPolarity::Positive,
+ })
})
.to_predicate(tcx)
}
};
}
+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;
}
}
+impl<'tcx> Relate<'tcx> for ty::ImplPolarity {
+ fn relate<R: TypeRelation<'tcx>>(
+ relation: &mut R,
+ a: ty::ImplPolarity,
+ b: ty::ImplPolarity,
+ ) -> RelateResult<'tcx, ty::ImplPolarity> {
+ if a != b {
+ Err(TypeError::PolarityMismatch(expected_found(relation, a, b)))
+ } else {
+ Ok(a)
+ }
+ }
+}
+
impl<'tcx> Relate<'tcx> for ty::TraitPredicate<'tcx> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
Ok(ty::TraitPredicate {
trait_ref: relation.relate(a.trait_ref, b.trait_ref)?,
constness: relation.relate(a.constness, b.constness)?,
+ polarity: relation.relate(a.polarity, b.polarity)?,
})
}
}
if let ty::BoundConstness::ConstIfConst = self.constness {
write!(f, "~const ")?;
}
- write!(f, "TraitPredicate({:?})", self.trait_ref)
+ write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity)
}
}
impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
type Lifted = ty::TraitPredicate<'tcx>;
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
- tcx.lift(self.trait_ref)
- .map(|trait_ref| ty::TraitPredicate { trait_ref, constness: self.constness })
+ tcx.lift(self.trait_ref).map(|trait_ref| ty::TraitPredicate {
+ trait_ref,
+ constness: self.constness,
+ polarity: self.polarity,
+ })
}
}
Some(match self {
Mismatch => Mismatch,
ConstnessMismatch(x) => ConstnessMismatch(x),
+ PolarityMismatch(x) => PolarityMismatch(x),
UnsafetyMismatch(x) => UnsafetyMismatch(x),
AbiMismatch(x) => AbiMismatch(x),
Mutability => Mutability,
self.map_bound(|trait_ref| ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
})
}
}
traits::NonStructuralMatchTy::Opaque => {
"opaque types cannot be used in patterns".to_string()
}
+ traits::NonStructuralMatchTy::Closure => {
+ "closures cannot be used in patterns".to_string()
+ }
traits::NonStructuralMatchTy::Generator => {
"generators cannot be used in patterns".to_string()
}
}
}
+ /// 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()
#![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)]
//! This pass just dumps MIR at a specified point.
use std::borrow::Cow;
-use std::fmt;
use std::fs::File;
use std::io;
use crate::MirPass;
+use rustc_middle::mir::write_mir_pretty;
use rustc_middle::mir::Body;
-use rustc_middle::mir::{dump_enabled, dump_mir, write_mir_pretty};
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{OutputFilenames, OutputType};
fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
}
-pub struct Disambiguator {
- is_after: bool,
-}
-
-impl fmt::Display for Disambiguator {
- fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
- let title = if self.is_after { "after" } else { "before" };
- write!(formatter, "{}", title)
- }
-}
-
-pub fn on_mir_pass<'tcx>(
- tcx: TyCtxt<'tcx>,
- pass_num: &dyn fmt::Display,
- pass_name: &str,
- body: &Body<'tcx>,
- is_after: bool,
-) {
- if dump_enabled(tcx, pass_name, body.source.def_id()) {
- dump_mir(tcx, Some(pass_num), pass_name, &Disambiguator { is_after }, body, |_, _| Ok(()));
- }
-}
-
pub fn emit_mir(tcx: TyCtxt<'_>, outputs: &OutputFilenames) -> io::Result<()> {
let path = outputs.path(OutputType::Mir);
let mut f = io::BufWriter::new(File::create(&path)?);
#![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)]
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_index::vec::IndexVec;
use rustc_middle::mir::visit::Visitor as _;
-use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
+use rustc_middle::mir::{dump_mir, traversal, Body, ConstQualifs, MirPhase, Promoted};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_span::{Span, Symbol};
mod remove_unneeded_drops;
mod remove_zsts;
mod required_consts;
+mod reveal_all;
mod separate_const_switch;
mod shim;
mod simplify;
let mut index = 0;
let mut run_pass = |pass: &dyn MirPass<'tcx>| {
let run_hooks = |body: &_, index, is_after| {
- dump_mir::on_mir_pass(
+ let disambiguator = if is_after { "after" } else { "before" };
+ dump_mir(
tcx,
- &format_args!("{:03}-{:03}", phase_index, index),
+ Some(&format_args!("{:03}-{:03}", phase_index, index)),
&pass.name(),
+ &disambiguator,
body,
- is_after,
+ |_, _| Ok(()),
);
};
run_hooks(body, index, false);
// to them. We run some optimizations before that, because they may be harder to do on the state
// machine than on MIR with async primitives.
let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[
+ &reveal_all::RevealAll, // has to be done before inlining, since inlined code is in RevealAll mode.
&lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
&normalize_array_len::NormalizeArrayLen, // has to run after `slice::len` lowering
&unreachable_prop::UnreachablePropagation,
trace!("Running RemoveUnneededDrops on {:?}", body.source);
let did = body.source.def_id();
- let param_env = tcx.param_env(did);
+ let param_env = tcx.param_env_reveal_all_normalized(did);
let mut should_simplify = false;
let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
--- /dev/null
+//! Normalizes MIR in RevealAll mode.
+
+use crate::MirPass;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{self, Ty, TyCtxt};
+
+pub struct RevealAll;
+
+impl<'tcx> MirPass<'tcx> for RevealAll {
+ 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))
+ && body.generator.is_none()
+ {
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+ RevealAllVisitor { tcx, param_env }.visit_body(body);
+ }
+ }
+}
+
+struct RevealAllVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
+ #[inline]
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ #[inline]
+ fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
+ *ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
+ }
+
+ #[inline]
+ fn process_projection_elem(
+ &mut self,
+ elem: PlaceElem<'tcx>,
+ _: Location,
+ ) -> Option<PlaceElem<'tcx>> {
+ match elem {
+ PlaceElem::Field(field, ty) => {
+ let new_ty = self.tcx.normalize_erasing_regions(self.param_env, ty);
+ if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
+ }
+ // None of those contain a Ty.
+ PlaceElem::Index(..)
+ | PlaceElem::Deref
+ | PlaceElem::ConstantIndex { .. }
+ | PlaceElem::Subslice { .. }
+ | PlaceElem::Downcast(..) => None,
+ }
+ }
+}
} else if self.eat_keyword(kw::Macro) {
// MACROS 2.0 ITEM
self.parse_item_decl_macro(lo)?
- } else if self.is_macro_rules_item() {
+ } else if let IsMacroRulesItem::Yes { has_bang } = self.is_macro_rules_item() {
// MACRO_RULES ITEM
- self.parse_item_macro_rules(vis)?
+ self.parse_item_macro_rules(vis, has_bang)?
} else if vis.kind.is_pub() && self.isnt_macro_invocation() {
self.recover_missing_kw_before_item()?;
return Ok(None);
|| self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }`
|| self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }`
|| self.is_async_fn() // no(2015): `async::b`, yes: `async fn`
- || self.is_macro_rules_item() // no: `macro_rules::b`, yes: `macro_rules! mac`
+ || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac`
}
/// Are we sure this could not possibly be a macro invocation?
Ok((ident, ItemKind::MacroDef(ast::MacroDef { body, macro_rules: false })))
}
- /// Is this unambiguously the start of a `macro_rules! foo` item definition?
- fn is_macro_rules_item(&mut self) -> bool {
- self.check_keyword(kw::MacroRules)
- && self.look_ahead(1, |t| *t == token::Not)
- && self.look_ahead(2, |t| t.is_ident())
+ /// Is this a possibly malformed start of a `macro_rules! foo` item definition?
+
+ fn is_macro_rules_item(&mut self) -> IsMacroRulesItem {
+ if self.check_keyword(kw::MacroRules) {
+ let macro_rules_span = self.token.span;
+
+ if self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) {
+ return IsMacroRulesItem::Yes { has_bang: true };
+ } else if self.look_ahead(1, |t| (t.is_ident())) {
+ // macro_rules foo
+ self.struct_span_err(macro_rules_span, "expected `!` after `macro_rules`")
+ .span_suggestion(
+ macro_rules_span,
+ "add a `!`",
+ "macro_rules!".to_owned(),
+ Applicability::MachineApplicable,
+ )
+ .emit();
+
+ return IsMacroRulesItem::Yes { has_bang: false };
+ }
+ }
+
+ IsMacroRulesItem::No
}
/// Parses a `macro_rules! foo { ... }` declarative macro.
- fn parse_item_macro_rules(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo> {
+ fn parse_item_macro_rules(
+ &mut self,
+ vis: &Visibility,
+ has_bang: bool,
+ ) -> PResult<'a, ItemInfo> {
self.expect_keyword(kw::MacroRules)?; // `macro_rules`
- self.expect(&token::Not)?; // `!`
+ if has_bang {
+ self.expect(&token::Not)?; // `!`
+ }
let ident = self.parse_ident()?;
if self.eat(&token::Not) {
}
}
}
+
+enum IsMacroRulesItem {
+ Yes { has_bang: bool },
+ No,
+}
"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();
},
);
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::BreakTy> {
match predicate.kind().skip_binder() {
- ty::PredicateKind::Trait(ty::TraitPredicate { trait_ref, constness: _ }) => {
- self.visit_trait(trait_ref)
- }
+ ty::PredicateKind::Trait(ty::TraitPredicate {
+ trait_ref,
+ constness: _,
+ polarity: _,
+ }) => self.visit_trait(trait_ref),
ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
ty.visit_with(self)?;
self.visit_projection_ty(projection_ty)
#[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, Some(value)) {
+ 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, None) {
+ 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);
}
}
}
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, Option<&V>) -> 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, value: Option<&V>) -> bool {
- (self.cache_on_disk)(tcx, key, value)
- }
-
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, _: Option<&Self::Value>) -> 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, None) {
+ 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());
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);
}
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
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 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);
}
}
descr: "module",
path,
accessible: true,
+ note: None,
},
));
} else {
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"
}
}
}
}
}
+/// The different settings that can be enabled via the `-Z location-detail` flag.
+#[derive(Clone, PartialEq, Hash, Debug)]
+pub struct LocationDetail {
+ pub file: bool,
+ pub line: bool,
+ pub column: bool,
+}
+
+impl LocationDetail {
+ pub fn all() -> Self {
+ Self { file: true, line: true, column: true }
+ }
+}
+
#[derive(Clone, PartialEq, Hash, Debug)]
pub enum SwitchWithOptPath {
Enabled(Option<PathBuf>),
use super::LdImpl;
use super::{
CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
- LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
+ LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
};
use crate::lint;
Option<LdImpl>,
OutputType,
RealFileName,
+ LocationDetail,
);
impl<T1, T2> DepTrackingHash for (T1, T2)
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`";
"either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted";
pub const parse_linker_plugin_lto: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), or the path to the linker plugin";
+ pub const parse_location_detail: &str =
+ "comma seperated list of location details to track: `file`, `line`, or `column`";
pub const parse_switch_with_opt_path: &str =
"an optional path to the profiling data output directory";
pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
}
}
+ crate fn parse_location_detail(ld: &mut LocationDetail, v: Option<&str>) -> bool {
+ if let Some(v) = v {
+ ld.line = false;
+ ld.file = false;
+ ld.column = false;
+ for s in v.split(',') {
+ match s {
+ "file" => ld.file = true,
+ "line" => ld.line = true,
+ "column" => ld.column = true,
+ _ => return false,
+ }
+ }
+ true
+ } else {
+ false
+ }
+ }
+
crate fn parse_opt_comma_list(slot: &mut Option<Vec<String>>, v: Option<&str>) -> bool {
match v {
Some(s) => {
for s in v.split(',') {
*slot |= match s {
"address" => SanitizerSet::ADDRESS,
+ "cfi" => SanitizerSet::CFI,
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"thread" => SanitizerSet::THREAD,
"a list LLVM plugins to enable (space separated)"),
llvm_time_trace: bool = (false, parse_bool, [UNTRACKED],
"generate JSON tracing data file from LLVM data (default: no)"),
+ location_detail: LocationDetail = (LocationDetail::all(), parse_location_detail, [TRACKED],
+ "comma seperated list of location details to be tracked when using caller_location \
+ valid options are `file`, `line`, and `column` (default: all)"),
ls: bool = (false, parse_bool, [UNTRACKED],
"list the symbols defined by a library crate (default: no)"),
macro_backtrace: 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],
}
}
- pub fn with_silent_emitter() -> Self {
+ pub fn with_silent_emitter(fatal_note: Option<String>) -> Self {
let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
- let handler = Handler::with_emitter(false, None, Box::new(SilentEmitter));
+ let fatal_handler = Handler::with_tty_emitter(ColorConfig::Auto, false, None, None);
+ let handler = Handler::with_emitter(
+ false,
+ None,
+ Box::new(SilentEmitter { fatal_handler, fatal_note }),
+ );
ParseSess::with_span_handler(handler, sm)
}
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.
cfg_target_thread_local,
cfg_target_vendor,
cfg_version,
+ cfi,
char,
client,
clippy,
rustc_specialization_trait,
rustc_stable,
rustc_std_internal_symbol,
+ rustc_strict_coherence,
rustc_symbol_name,
rustc_synthetic,
rustc_test_marker,
type_alias_enum_variants,
type_alias_impl_trait,
type_ascription,
+ type_changing_struct_update,
type_id,
type_length_limit,
type_macros,
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.
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());
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()
mcount: "\u{1}_mcount".to_string(),
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
| SanitizerSet::LEAK
| SanitizerSet::MEMORY
| SanitizerSet::THREAD
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,
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,
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(),
-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
substs: infcx.tcx.mk_substs_trait(ty, &[]),
},
constness: ty::BoundConstness::NotConst,
+ // Auto traits are positive
+ polarity: ty::ImplPolarity::Positive,
}));
let computed_preds = param_env.caller_bounds().iter();
//! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::select::IntercrateAmbiguityCause;
use crate::traits::SkipLeakCheck;
-use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext};
+use crate::traits::{
+ self, Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext,
+};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::Subst;
b_def_id: DefId,
snapshot: &CombinedSnapshot<'_, 'tcx>,
) -> Option<OverlapResult<'tcx>> {
+ fn loose_check(selcx: &mut SelectionContext<'cx, 'tcx>, o: &PredicateObligation<'tcx>) -> bool {
+ !selcx.predicate_may_hold_fatal(o)
+ }
+
+ fn strict_check(selcx: &SelectionContext<'cx, 'tcx>, o: &PredicateObligation<'tcx>) -> bool {
+ let infcx = selcx.infcx();
+ let tcx = infcx.tcx;
+ o.flip_polarity(tcx)
+ .as_ref()
+ .map(|o| selcx.infcx().predicate_must_hold_modulo_regions(o))
+ .unwrap_or(false)
+ }
+
// For the purposes of this check, we don't bring any placeholder
// types into scope; instead, we replace the generic types with
// fresh type variables, and hence we do our evaluations in an
debug!("overlap: unification check succeeded");
- // Are any of the obligations unsatisfiable? If so, no overlap.
+ // There's no overlap if obligations are unsatisfiable or if the obligation negated is
+ // satisfied.
+ //
+ // For example, given these two impl headers:
+ //
+ // `impl<'a> From<&'a str> for Box<dyn Error>`
+ // `impl<E> From<E> for Box<dyn Error> where E: Error`
+ //
+ // So we have:
+ //
+ // `Box<dyn Error>: From<&'?a str>`
+ // `Box<dyn Error>: From<?E>`
+ //
+ // After equating the two headers:
+ //
+ // `Box<dyn Error> = Box<dyn Error>`
+ // So, `?E = &'?a str` and then given the where clause `&'?a str: Error`.
+ //
+ // If the obligation `&'?a str: Error` holds, it means that there's overlap. If that doesn't
+ // hold we need to check if `&'?a str: !Error` holds, if doesn't hold there's overlap because
+ // at some point an impl for `&'?a str: Error` could be added.
let infcx = selcx.infcx();
+ let tcx = infcx.tcx;
let opt_failing_obligation = a_impl_header
.predicates
.iter()
predicate: p,
})
.chain(obligations)
- .find(|o| !selcx.predicate_may_hold_fatal(o));
+ .find(|o| {
+ // if both impl headers are set to strict coherence it means that this will be accepted
+ // only if it's stated that T: !Trait. So only prove that the negated obligation holds.
+ if tcx.has_attr(a_def_id, sym::rustc_strict_coherence)
+ && tcx.has_attr(b_def_id, sym::rustc_strict_coherence)
+ {
+ strict_check(selcx, o)
+ } else {
+ loose_check(selcx, o) || tcx.features().negative_impls && strict_check(selcx, o)
+ }
+ });
// FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
// to the canonical trait query form, `infcx.predicate_may_hold`, once
// the new system supports intercrate mode (which coherence needs).
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::query::normalize::AtExt as _;
+use crate::traits::specialize::to_pretty_impl_header;
use on_unimplemented::InferCtxtExt as _;
use suggestions::InferCtxtExt as _;
let mut span = obligation.cause.span;
let mut err = match *error {
+ SelectionError::Ambiguous(ref impls) => {
+ let mut err = self.tcx.sess.struct_span_err(
+ obligation.cause.span,
+ &format!("multiple applicable `impl`s for `{}`", obligation.predicate),
+ );
+ self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate);
+ err.emit();
+ return;
+ }
SelectionError::Unimplemented => {
// If this obligation was generated as a result of well-formedness checking, see if we
// can get a better error message by performing HIR-based well-formedness checking.
obligation: &PredicateObligation<'tcx>,
);
+ fn annotate_source_of_ambiguity(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ impls: &[DefId],
+ predicate: ty::Predicate<'tcx>,
+ );
+
fn maybe_suggest_unsized_generics(
&self,
err: &mut DiagnosticBuilder<'tcx>,
}
}
}
+ ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+ self.get_parent_trait_ref(&parent_code)
+ }
_ => None,
}
}
?predicate, ?obligation.cause.code,
);
- // Ambiguity errors are often caused as fallout from earlier
- // errors. So just ignore them if this infcx is tainted.
- if self.is_tainted_by_errors() {
- return;
- }
+ // Ambiguity errors are often caused as fallout from earlier errors.
+ // We ignore them if this `infcx` is tainted in some cases below.
let bound_predicate = predicate.kind();
let mut err = match bound_predicate.skip_binder() {
// check upstream for type errors and don't add the obligations to
// begin with in those cases.
if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) {
- self.emit_inference_failure_err(body_id, span, subst, vec![], ErrorCode::E0282)
+ if !self.is_tainted_by_errors() {
+ self.emit_inference_failure_err(
+ body_id,
+ span,
+ subst,
+ vec![],
+ ErrorCode::E0282,
+ )
.emit();
+ }
return;
}
+
let impl_candidates = self.find_similar_impl_candidates(trait_ref);
let mut err = self.emit_inference_failure_err(
body_id,
impl_candidates,
ErrorCode::E0283,
);
- err.note(&format!("cannot satisfy `{}`", predicate));
+
+ let obligation = Obligation::new(
+ obligation.cause.clone(),
+ obligation.param_env,
+ trait_ref.to_poly_trait_predicate(),
+ );
+ let mut selcx = SelectionContext::with_query_mode(
+ &self,
+ crate::traits::TraitQueryMode::Standard,
+ );
+ match selcx.select_from_obligation(&obligation) {
+ Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
+ self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+ }
+ _ => {
+ if self.is_tainted_by_errors() {
+ err.cancel();
+ return;
+ }
+ err.note(&format!("cannot satisfy `{}`", predicate));
+ }
+ }
+
if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code {
self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
} else if let (
ty::PredicateKind::WellFormed(arg) => {
// Same hacky approach as above to avoid deluging user
// with error messages.
- if arg.references_error() || self.tcx.sess.has_errors() {
+ if arg.references_error()
+ || self.tcx.sess.has_errors()
+ || self.is_tainted_by_errors()
+ {
return;
}
}
ty::PredicateKind::Subtype(data) => {
- if data.references_error() || self.tcx.sess.has_errors() {
+ if data.references_error()
+ || self.tcx.sess.has_errors()
+ || self.is_tainted_by_errors()
+ {
// no need to overload user in such cases
return;
}
ty::PredicateKind::Projection(data) => {
let self_ty = data.projection_ty.self_ty();
let ty = data.ty;
- if predicate.references_error() {
+ if predicate.references_error() || self.is_tainted_by_errors() {
return;
}
if self_ty.needs_infer() && ty.needs_infer() {
}
_ => {
- if self.tcx.sess.has_errors() {
+ if self.tcx.sess.has_errors() || self.is_tainted_by_errors() {
return;
}
let mut err = struct_span_err!(
err.emit();
}
+ fn annotate_source_of_ambiguity(
+ &self,
+ err: &mut DiagnosticBuilder<'tcx>,
+ impls: &[DefId],
+ predicate: ty::Predicate<'tcx>,
+ ) {
+ let mut spans = vec![];
+ let mut crates = vec![];
+ let mut post = vec![];
+ for def_id in impls {
+ match self.tcx.span_of_impl(*def_id) {
+ Ok(span) => spans.push(self.tcx.sess.source_map().guess_head_span(span)),
+ Err(name) => {
+ crates.push(name);
+ if let Some(header) = to_pretty_impl_header(self.tcx, *def_id) {
+ post.push(header);
+ }
+ }
+ }
+ }
+ let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+ let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
+ crate_names.sort();
+ crate_names.dedup();
+ post.sort();
+ post.dedup();
+
+ if self.is_tainted_by_errors()
+ && crate_names.len() == 1
+ && crate_names[0] == "`core`"
+ && spans.len() == 0
+ {
+ // Avoid complaining about other inference issues for expressions like
+ // `42 >> 1`, where the types are still `{integer}`, but we want to
+ // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
+ err.cancel();
+ return;
+ }
+ let post = if post.len() > 4 {
+ format!(
+ ":\n{}\nand {} more",
+ 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")) {
+ format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
+ } else if post.len() == 1 {
+ format!(": `{}`", post[0])
+ } else {
+ String::new()
+ };
+
+ match (spans.len(), crates.len(), crate_names.len()) {
+ (0, 0, 0) => {
+ err.note(&format!("cannot satisfy `{}`", predicate));
+ }
+ (0, _, 1) => {
+ err.note(&format!("{} in the `{}` crate{}", msg, crates[0], post,));
+ }
+ (0, _, _) => {
+ err.note(&format!(
+ "{} in the following crates: {}{}",
+ msg,
+ crate_names.join(", "),
+ post,
+ ));
+ }
+ (_, 0, 0) => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, &msg);
+ }
+ (_, 1, 1) => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, &msg);
+ err.note(
+ &format!("and another `impl` found in the `{}` crate{}", crates[0], post,),
+ );
+ }
+ _ => {
+ let span: MultiSpan = spans.into();
+ err.span_note(span, &msg);
+ err.note(&format!(
+ "and more `impl`s found in the following crates: {}{}",
+ crate_names.join(", "),
+ post,
+ ));
+ }
+ }
+ }
+
/// Returns `true` if the trait predicate may apply for *some* assignment
/// to the type parameters.
fn predicate_can_apply(
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>>,
);
generics,
trait_ref.without_const().to_predicate(tcx).to_string(),
),
- (None, Some((ident, []))) => (
- ident.span.shrink_to_hi(),
- format!(": {}", trait_ref.print_only_trait_path().to_string()),
- ),
- (_, Some((_, [.., bounds]))) => (
- bounds.span().shrink_to_hi(),
- format!(" + {}", trait_ref.print_only_trait_path().to_string()),
- ),
- (Some(_), Some((_, []))) => (
- generics.span.shrink_to_hi(),
- format!(": {}", trait_ref.print_only_trait_path().to_string()),
- ),
+ (None, Some((ident, []))) => {
+ (ident.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
+ }
+ (_, Some((_, [.., bounds]))) => {
+ (bounds.span().shrink_to_hi(), format!(" + {}", trait_ref.print_only_trait_path()))
+ }
+ (Some(_), Some((_, []))) => {
+ (generics.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
+ }
};
err.span_suggestion_verbose(
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);
debug!(
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",
- );
+ );
+ }
}
}
}
ty::Binder::dummy(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
}),
);
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: predicate.constness,
+ polarity: predicate.polarity,
})
})
.to_predicate(infcx.tcx),
use crate::traits::coherence::Conflict;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{util, SelectionResult};
-use crate::traits::{ErrorReporting, Overflow, Unimplemented};
+use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented};
use super::BuiltinImplConditions;
use super::IntercrateAmbiguityCause;
return Ok(None);
}
- let mut candidates = candidate_set.vec;
+ let candidates = candidate_set.vec;
debug!(?stack, ?candidates, "assembled {} candidates", candidates.len());
// candidate which assumes $0 == int, one that assumes `$0 ==
// usize`, etc. This spells an ambiguity.
+ let mut candidates = self.filter_impls(candidates, stack.obligation);
+
// If there is more than one candidate, first winnow them down
// by considering extra conditions (nested obligations and so
// forth). We don't winnow if there is exactly one
// Instead, we select the right impl now but report "`Bar` does
// not implement `Clone`".
if candidates.len() == 1 {
- return self.filter_impls(candidates.pop().unwrap(), stack.obligation);
+ return self.filter_reservation_impls(candidates.pop().unwrap(), stack.obligation);
}
// Winnow, but record the exact outcome of evaluation, which
// and report ambiguity.
if i > 1 {
debug!("multiple matches, ambig");
- return Ok(None);
+ return Err(Ambiguous(
+ candidates
+ .into_iter()
+ .filter_map(|c| match c.candidate {
+ SelectionCandidate::ImplCandidate(def_id) => Some(def_id),
+ _ => None,
+ })
+ .collect(),
+ ));
}
}
}
}
// Just one candidate left.
- self.filter_impls(candidates.pop().unwrap().candidate, stack.obligation)
+ self.filter_reservation_impls(candidates.pop().unwrap().candidate, stack.obligation)
}
#[instrument(skip(self, stack), level = "debug")]
let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
- self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
-
- // Other bounds. Consider both in-scope bounds from fn decl
- // and applicable impls. There is a certain set of precedence rules here.
- let def_id = obligation.predicate.def_id();
- let lang_items = self.tcx().lang_items();
-
- if lang_items.copy_trait() == Some(def_id) {
- debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
-
- // User-defined copy impls are permitted, but only for
- // structs and enums.
+ // The only way to prove a NotImplemented(T: Foo) predicate is via a negative impl.
+ // There are no compiler built-in rules for this.
+ if obligation.polarity() == ty::ImplPolarity::Negative {
+ self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
self.assemble_candidates_from_impls(obligation, &mut candidates);
-
- // For other types, we'll use the builtin rules.
- let copy_conditions = self.copy_clone_conditions(obligation);
- self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
- } else if lang_items.discriminant_kind_trait() == Some(def_id) {
- // `DiscriminantKind` is automatically implemented for every type.
- candidates.vec.push(DiscriminantKindCandidate);
- } else if lang_items.pointee_trait() == Some(def_id) {
- // `Pointee` is automatically implemented for every type.
- candidates.vec.push(PointeeCandidate);
- } else if lang_items.sized_trait() == Some(def_id) {
- // Sized is never implementable by end-users, it is
- // always automatically computed.
- let sized_conditions = self.sized_conditions(obligation);
- self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
- } else if lang_items.unsize_trait() == Some(def_id) {
- self.assemble_candidates_for_unsizing(obligation, &mut candidates);
- } else if lang_items.drop_trait() == Some(def_id)
- && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
- {
- if self.is_in_const_context {
- self.assemble_const_drop_candidates(obligation, &mut candidates)?;
- } else {
- debug!("passing ~const Drop bound; in non-const context");
- // `~const Drop` when we are not in a const context has no effect.
- candidates.vec.push(ConstDropCandidate)
- }
} else {
- if lang_items.clone_trait() == Some(def_id) {
- // Same builtin conditions as `Copy`, i.e., every type which has builtin support
- // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
- // types have builtin support for `Clone`.
- let clone_conditions = self.copy_clone_conditions(obligation);
- self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
- }
+ self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
+
+ // Other bounds. Consider both in-scope bounds from fn decl
+ // and applicable impls. There is a certain set of precedence rules here.
+ let def_id = obligation.predicate.def_id();
+ let lang_items = self.tcx().lang_items();
+
+ if lang_items.copy_trait() == Some(def_id) {
+ debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty());
+
+ // User-defined copy impls are permitted, but only for
+ // structs and enums.
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
+
+ // For other types, we'll use the builtin rules.
+ let copy_conditions = self.copy_clone_conditions(obligation);
+ self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
+ } else if lang_items.discriminant_kind_trait() == Some(def_id) {
+ // `DiscriminantKind` is automatically implemented for every type.
+ candidates.vec.push(DiscriminantKindCandidate);
+ } else if lang_items.pointee_trait() == Some(def_id) {
+ // `Pointee` is automatically implemented for every type.
+ candidates.vec.push(PointeeCandidate);
+ } else if lang_items.sized_trait() == Some(def_id) {
+ // Sized is never implementable by end-users, it is
+ // always automatically computed.
+ let sized_conditions = self.sized_conditions(obligation);
+ self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
+ } else if lang_items.unsize_trait() == Some(def_id) {
+ self.assemble_candidates_for_unsizing(obligation, &mut candidates);
+ } else if lang_items.drop_trait() == Some(def_id)
+ && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
+ {
+ if self.is_in_const_context {
+ self.assemble_const_drop_candidates(obligation, &mut candidates)?;
+ } else {
+ debug!("passing ~const Drop bound; in non-const context");
+ // `~const Drop` when we are not in a const context has no effect.
+ candidates.vec.push(ConstDropCandidate)
+ }
+ } else {
+ if lang_items.clone_trait() == Some(def_id) {
+ // Same builtin conditions as `Copy`, i.e., every type which has builtin support
+ // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone`
+ // types have builtin support for `Clone`.
+ let clone_conditions = self.copy_clone_conditions(obligation);
+ self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
+ }
- self.assemble_generator_candidates(obligation, &mut candidates);
- self.assemble_closure_candidates(obligation, &mut candidates);
- self.assemble_fn_pointer_candidates(obligation, &mut candidates);
- self.assemble_candidates_from_impls(obligation, &mut candidates);
- self.assemble_candidates_from_object_ty(obligation, &mut candidates);
- }
+ self.assemble_generator_candidates(obligation, &mut candidates);
+ self.assemble_closure_candidates(obligation, &mut candidates);
+ self.assemble_fn_pointer_candidates(obligation, &mut candidates);
+ self.assemble_candidates_from_impls(obligation, &mut candidates);
+ self.assemble_candidates_from_object_ty(obligation, &mut candidates);
+ }
- self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
- self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
- // Auto implementations have lower priority, so we only
- // consider triggering a default if there is no other impl that can apply.
- if candidates.vec.is_empty() {
- self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
+ self.assemble_candidates_from_projected_tys(obligation, &mut candidates);
+ self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
+ // Auto implementations have lower priority, so we only
+ // consider triggering a default if there is no other impl that can apply.
+ if candidates.vec.is_empty() {
+ self.assemble_candidates_from_auto_impls(obligation, &mut candidates);
+ }
}
debug!("candidate list size: {}", candidates.vec.len());
Ok(candidates)
for bound in matching_bounds {
let wc = self.evaluate_where_clause(stack, bound.value)?;
if wc.may_apply() {
- candidates.vec.push(ParamCandidate(bound));
+ candidates.vec.push(ParamCandidate((bound, stack.obligation.polarity())));
}
}
substs: self.tcx().mk_substs_trait(ty, &[]),
},
constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
}));
copy_obligation.recursion_depth = depth + 1;
self.assemble_candidates_from_impls(©_obligation, &mut copy_candidates);
}
ParamCandidate(param) => {
- let obligations = self.confirm_param_candidate(obligation, param.value);
- Ok(ImplSource::Param(obligations, param.constness))
+ let obligations = self.confirm_param_candidate(obligation, param.0.value);
+ Ok(ImplSource::Param(obligations, param.0.constness))
}
ImplCandidate(impl_def_id) => {
use super::Selection;
use super::SelectionResult;
use super::TraitQueryMode;
-use super::{ErrorReporting, Overflow, SelectionError, Unimplemented};
+use super::{ErrorReporting, Overflow, SelectionError};
use super::{ObligationCause, PredicateObligation, TraitObligation};
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
&mut self,
obligation: &TraitObligation<'tcx>,
) -> SelectionResult<'tcx, Selection<'tcx>> {
- debug_assert!(!obligation.predicate.has_escaping_bound_vars());
-
- let pec = &ProvisionalEvaluationCache::default();
- let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
-
- let candidate = match self.candidate_from_obligation(&stack) {
+ let candidate = match self.select_from_obligation(obligation) {
Err(SelectionError::Overflow) => {
// In standard mode, overflow must have been caught and reported
// earlier.
assert!(self.query_mode == TraitQueryMode::Canonical);
return Err(SelectionError::Overflow);
}
+ Err(SelectionError::Ambiguous(_)) => {
+ return Ok(None);
+ }
Err(e) => {
return Err(e);
}
}
}
+ crate fn select_from_obligation(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ debug_assert!(!obligation.predicate.has_escaping_bound_vars());
+
+ let pec = &ProvisionalEvaluationCache::default();
+ let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation);
+
+ self.candidate_from_obligation(&stack)
+ }
+
///////////////////////////////////////////////////////////////////////////
// EVALUATION
//
debug!(?fresh_trait_ref);
- if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
+ if let Some(result) = self.check_evaluation_cache(
+ obligation.param_env,
+ fresh_trait_ref,
+ obligation.polarity(),
+ ) {
debug!(?result, "CACHE HIT");
return Ok(result);
}
let reached_depth = stack.reached_depth.get();
if reached_depth >= stack.depth {
debug!(?result, "CACHE MISS");
- self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
+ self.insert_evaluation_cache(
+ obligation.param_env,
+ fresh_trait_ref,
+ obligation.polarity(),
+ dep_node,
+ result,
+ );
stack.cache().on_completion(stack.dfn, |fresh_trait_ref, provisional_result| {
self.insert_evaluation_cache(
obligation.param_env,
fresh_trait_ref,
+ obligation.polarity(),
dep_node,
provisional_result.max(result),
);
// precise still.
let unbound_input_types =
stack.fresh_trait_ref.value.skip_binder().substs.types().any(|ty| ty.is_fresh());
- // This check was an imperfect workaround for a bug in the old
- // intercrate mode; it should be removed when that goes away.
- if unbound_input_types && self.intercrate {
- debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",);
- // Heuristics: show the diagnostics when there are no candidates in crate.
- if self.intercrate_ambiguity_causes.is_some() {
- debug!("evaluate_stack: intercrate_ambiguity_causes is some");
- if let Ok(candidate_set) = self.assemble_candidates(stack) {
- if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
- let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
- let self_ty = trait_ref.self_ty();
- let cause =
- with_no_trimmed_paths(|| IntercrateAmbiguityCause::DownstreamCrate {
- trait_desc: trait_ref.print_only_trait_path().to_string(),
- self_desc: if self_ty.has_concrete_skeleton() {
- Some(self_ty.to_string())
- } else {
- None
- },
+
+ if stack.obligation.polarity() != ty::ImplPolarity::Negative {
+ // This check was an imperfect workaround for a bug in the old
+ // intercrate mode; it should be removed when that goes away.
+ if unbound_input_types && self.intercrate {
+ debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",);
+ // Heuristics: show the diagnostics when there are no candidates in crate.
+ if self.intercrate_ambiguity_causes.is_some() {
+ debug!("evaluate_stack: intercrate_ambiguity_causes is some");
+ if let Ok(candidate_set) = self.assemble_candidates(stack) {
+ if !candidate_set.ambiguous && candidate_set.vec.is_empty() {
+ let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
+ let self_ty = trait_ref.self_ty();
+ let cause = with_no_trimmed_paths(|| {
+ IntercrateAmbiguityCause::DownstreamCrate {
+ trait_desc: trait_ref.print_only_trait_path().to_string(),
+ self_desc: if self_ty.has_concrete_skeleton() {
+ Some(self_ty.to_string())
+ } else {
+ None
+ },
+ }
});
- debug!(?cause, "evaluate_stack: pushing cause");
- self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ debug!(?cause, "evaluate_stack: pushing cause");
+ self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause);
+ }
}
}
+ return Ok(EvaluatedToAmbig);
}
- return Ok(EvaluatedToAmbig);
}
+
if unbound_input_types
&& stack.iter().skip(1).any(|prev| {
stack.obligation.param_env == prev.obligation.param_env
match self.candidate_from_obligation(stack) {
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
+ Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
Ok(None) => Ok(EvaluatedToAmbig),
Err(Overflow) => Err(OverflowError::Canonical),
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
&self,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+ polarity: ty::ImplPolarity,
) -> Option<EvaluationResult> {
// Neither the global nor local cache is aware of intercrate
// mode, so don't do any caching. In particular, we might
let tcx = self.tcx();
if self.can_use_global_caches(param_env) {
- if let Some(res) = tcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx) {
+ if let Some(res) = tcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
+ {
return Some(res);
}
}
- self.infcx.evaluation_cache.get(¶m_env.and(trait_ref), tcx)
+ self.infcx.evaluation_cache.get(&(param_env.and(trait_ref), polarity), tcx)
}
fn insert_evaluation_cache(
&mut self,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::ConstnessAnd<ty::PolyTraitRef<'tcx>>,
+ polarity: ty::ImplPolarity,
dep_node: DepNodeIndex,
result: EvaluationResult,
) {
// FIXME: Due to #50507 this overwrites the different values
// This should be changed to use HashMapExt::insert_same
// when that is fixed
- self.tcx().evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
+ self.tcx().evaluation_cache.insert(
+ (param_env.and(trait_ref), polarity),
+ dep_node,
+ result,
+ );
return;
}
}
debug!(?trait_ref, ?result, "insert_evaluation_cache");
- self.infcx.evaluation_cache.insert(param_env.and(trait_ref), dep_node, result);
+ self.infcx.evaluation_cache.insert((param_env.and(trait_ref), polarity), dep_node, result);
}
/// For various reasons, it's possible for a subobligation
(result, dep_node)
}
+ /// filter_impls filters constant trait obligations and candidates that have a positive impl
+ /// for a negative goal and a negative impl for a positive goal
#[instrument(level = "debug", skip(self))]
fn filter_impls(
&mut self,
- candidate: SelectionCandidate<'tcx>,
+ candidates: Vec<SelectionCandidate<'tcx>>,
obligation: &TraitObligation<'tcx>,
- ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ ) -> Vec<SelectionCandidate<'tcx>> {
let tcx = self.tcx();
- // Respect const trait obligations
- if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
- match candidate {
- // const impl
- ImplCandidate(def_id) if tcx.impl_constness(def_id) == hir::Constness::Const => {}
- // const param
- ParamCandidate(ty::ConstnessAnd {
- constness: ty::BoundConstness::ConstIfConst,
- ..
- }) => {}
- // auto trait impl
- AutoImplCandidate(..) => {}
- // generator, this will raise error in other places
- // or ignore error with const_async_blocks feature
- GeneratorCandidate => {}
- // FnDef where the function is const
- FnPointerCandidate { is_const: true } => {}
- ConstDropCandidate => {}
- _ => {
- // reject all other types of candidates
- return Err(Unimplemented);
+ let mut result = Vec::with_capacity(candidates.len());
+
+ for candidate in candidates {
+ // Respect const trait obligations
+ if self.is_trait_predicate_const(obligation.predicate.skip_binder()) {
+ match candidate {
+ // const impl
+ ImplCandidate(def_id)
+ if tcx.impl_constness(def_id) == hir::Constness::Const => {}
+ // const param
+ ParamCandidate((
+ ty::ConstnessAnd { constness: ty::BoundConstness::ConstIfConst, .. },
+ _,
+ )) => {}
+ // auto trait impl
+ AutoImplCandidate(..) => {}
+ // generator, this will raise error in other places
+ // or ignore error with const_async_blocks feature
+ GeneratorCandidate => {}
+ // FnDef where the function is const
+ FnPointerCandidate { is_const: true } => {}
+ ConstDropCandidate => {}
+ _ => {
+ // reject all other types of candidates
+ continue;
+ }
}
}
+
+ if let ImplCandidate(def_id) = candidate {
+ if ty::ImplPolarity::Reservation == tcx.impl_polarity(def_id)
+ || obligation.polarity() == tcx.impl_polarity(def_id)
+ || self.allow_negative_impls
+ {
+ result.push(candidate);
+ }
+ } else {
+ result.push(candidate);
+ }
}
- // Treat negative impls as unimplemented, and reservation impls as ambiguity.
+
+ result
+ }
+
+ /// filter_reservation_impls filter reservation impl for any goal as ambiguous
+ #[instrument(level = "debug", skip(self))]
+ fn filter_reservation_impls(
+ &mut self,
+ candidate: SelectionCandidate<'tcx>,
+ obligation: &TraitObligation<'tcx>,
+ ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> {
+ let tcx = self.tcx();
+ // Treat reservation impls as ambiguity.
if let ImplCandidate(def_id) = candidate {
- match tcx.impl_polarity(def_id) {
- ty::ImplPolarity::Negative if !self.allow_negative_impls => {
- return Err(Unimplemented);
- }
- ty::ImplPolarity::Reservation => {
- if let Some(intercrate_ambiguity_clauses) =
- &mut self.intercrate_ambiguity_causes
- {
- let attrs = tcx.get_attrs(def_id);
- let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
- let value = attr.and_then(|a| a.value_str());
- if let Some(value) = value {
- debug!(
- "filter_impls: \
+ if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) {
+ if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes {
+ let attrs = tcx.get_attrs(def_id);
+ let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
+ let value = attr.and_then(|a| a.value_str());
+ if let Some(value) = value {
+ debug!(
+ "filter_reservation_impls: \
reservation impl ambiguity on {:?}",
- def_id
- );
- intercrate_ambiguity_clauses.push(
- IntercrateAmbiguityCause::ReservationImpl {
- message: value.to_string(),
- },
- );
- }
+ def_id
+ );
+ intercrate_ambiguity_clauses.push(
+ IntercrateAmbiguityCause::ReservationImpl {
+ message: value.to_string(),
+ },
+ );
}
- return Ok(None);
}
- _ => {}
- };
+ return Ok(None);
+ }
}
Ok(Some(candidate))
}
fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> {
debug!("is_knowable(intercrate={:?})", self.intercrate);
- if !self.intercrate {
+ if !self.intercrate || stack.obligation.polarity() == ty::ImplPolarity::Negative {
return None;
}
if self.can_use_global_caches(param_env) {
if let Some(res) = tcx
.selection_cache
- .get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
+ .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
{
return Some(res);
}
}
self.infcx
.selection_cache
- .get(¶m_env.and(trait_ref).with_constness(pred.constness), tcx)
+ .get(&(param_env.and(trait_ref).with_constness(pred.constness), pred.polarity), tcx)
}
/// Determines whether can we safely cache the result
debug!(?trait_ref, ?candidate, "insert_candidate_cache global");
// This may overwrite the cache with the same value.
tcx.selection_cache.insert(
- param_env.and(trait_ref).with_constness(pred.constness),
+ (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
dep_node,
candidate,
);
debug!(?trait_ref, ?candidate, "insert_candidate_cache local");
self.infcx.selection_cache.insert(
- param_env.and(trait_ref).with_constness(pred.constness),
+ (param_env.and(trait_ref).with_constness(pred.constness), pred.polarity),
dep_node,
candidate,
);
| ConstDropCandidate,
) => false,
- (ParamCandidate(other), ParamCandidate(victim)) => {
+ (
+ ParamCandidate((other, other_polarity)),
+ ParamCandidate((victim, victim_polarity)),
+ ) => {
let same_except_bound_vars = other.value.skip_binder()
== victim.value.skip_binder()
&& other.constness == victim.constness
+ && other_polarity == victim_polarity
&& !other.value.skip_binder().has_escaping_bound_vars();
if same_except_bound_vars {
// See issue #84398. In short, we can generate multiple ParamCandidates which are
other.value.bound_vars().len() <= victim.value.bound_vars().len()
} else if other.value == victim.value
&& victim.constness == ty::BoundConstness::NotConst
+ && other_polarity == victim_polarity
{
// Drop otherwise equivalent non-const candidates in favor of const candidates.
true
| TraitAliasCandidate(..)
| ObjectCandidate(_)
| ProjectionCandidate(_),
- ) => !is_global(&cand.value),
+ ) => !is_global(&cand.0.value),
(ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(&cand.value)
+ is_global(&cand.0.value)
}
(
ImplCandidate(_)
) => {
// Prefer these to a global where-clause bound
// (see issue #50825).
- is_global(&cand.value) && other.evaluation.must_apply_modulo_regions()
+ is_global(&cand.0.value) && other.evaluation.must_apply_modulo_regions()
}
(ProjectionCandidate(i), ProjectionCandidate(j))
/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a
/// string.
-fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
+crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> {
use std::fmt::Write;
let trait_ref = tcx.impl_trait_ref(impl_def_id)?;
Dynamic,
Foreign,
Opaque,
+ Closure,
Generator,
Projection,
}
ty::Projection(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Projection);
}
+ ty::Closure(..) => {
+ return ControlFlow::Break(NonStructuralMatchTy::Closure);
+ }
ty::Generator(..) | ty::GeneratorWitness(..) => {
return ControlFlow::Break(NonStructuralMatchTy::Generator);
}
// First check all contained types and then tell the caller to continue searching.
return ty.super_visit_with(self);
}
- ty::Closure(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
+ ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => {
bug!("unexpected type during structural-match checking: {:?}", ty);
}
ty::Error(_) => {
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))
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,
substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
},
constness: t.constness,
+ polarity: t.polarity,
}));
let obl = Obligation::new(
o.cause.clone(),
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};
debug!("coerce: unsize not object safe");
return Err(TypeError::ObjectUnsafeCoercion(did));
}
- Err(_) => {}
+ Err(error) => {
+ debug!(?error, "coerce: unsize failed");
+ }
}
- debug!("coerce: unsize failed");
// Examine the supertype and consider auto-borrowing.
match *b.kind() {
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,
// `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;
}
}
}
..
},
method,
- )) if Some(recv_ty.def_id()) == pin_did && method.ident.name == sym::new => {
+ )) if recv_ty.opt_def_id() == pin_did && method.ident.name == sym::new => {
err.span_suggestion(
fn_name.span,
"use `Box::pin` to pin and box this expression",
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))
+ .map(|&d| d);
+
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
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
self.link_fn_params(body.params);
self.visit_body(body);
self.visit_region_obligations(body_id.hir_id);
-
- self.constrain_opaque_types();
}
fn visit_region_obligations(&mut self, hir_id: hir::HirId) {
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
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: _,
}) => {
if !matches!(
trait_predicate_kind(tcx, predicate),
ty::PredicateKind::Trait(ty::TraitPredicate {
trait_ref,
constness: ty::BoundConstness::NotConst,
+ polarity: _,
}) => Some(tcx.trait_def(trait_ref.def_id).specialization_kind),
ty::PredicateKind::Trait(_)
| ty::PredicateKind::RegionOutlives(_)
self.add_constraints_from_region(current, lt, variance_i)
}
GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
- GenericArgKind::Const(_) => {
- // Consts impose no constraints.
+ GenericArgKind::Const(val) => {
+ self.add_constraints_from_const(current, val, variance_i)
}
}
}
self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
}
- ty::Array(typ, _) => {
+ ty::Array(typ, len) => {
+ self.add_constraints_from_const(current, len, variance);
self.add_constraints_from_ty(current, typ, variance);
}
self.add_constraints_from_region(current, lt, variance_i)
}
GenericArgKind::Type(ty) => self.add_constraints_from_ty(current, ty, variance_i),
- GenericArgKind::Const(_) => {
- // Consts impose no constraints.
+ GenericArgKind::Const(val) => {
+ self.add_constraints_from_const(current, val, variance)
}
}
}
}
+ /// Adds constraints appropriate for a const expression `val`
+ /// in a context with ambient variance `variance`
+ fn add_constraints_from_const(
+ &mut self,
+ current: &CurrentItem,
+ val: &ty::Const<'tcx>,
+ variance: VarianceTermPtr<'a>,
+ ) {
+ debug!("add_constraints_from_const(val={:?}, variance={:?})", val, variance);
+
+ match &val.val {
+ ty::ConstKind::Unevaluated(uv) => {
+ let substs = uv.substs(self.tcx());
+ self.add_constraints_from_invariant_substs(current, substs, variance);
+ }
+ _ => {}
+ }
+ }
+
/// Adds constraints appropriate for a function with signature
/// `sig` appearing in a context with ambient variance `variance`
fn add_constraints_from_sig(
# Enable symbol-mangling-version v0. This can be helpful when profiling rustc,
# as generics will be preserved in symbols (rather than erased into opaque T).
-#new-symbol-mangling = false
+# When no setting is given, the new scheme will be used when compiling the
+# compiler and its tools and the legacy scheme will be used when compiling the
+# standard library.
+# If an explicit setting is given, it will be used for all parts of the codebase.
+#new-symbol-mangling = true|false (see comment)
# =============================================================================
# Options for specific targets
/// item's ordering relative to any other item, as determined by the [`Ord`]
/// trait, changes while it is in the heap. This is normally only possible
/// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The
-/// behavior resulting from such a logic error is not specified, but will
-/// not result in undefined behavior. This could include panics, incorrect
-/// results, aborts, memory leaks, and non-termination.
+/// behavior resulting from such a logic error is not specified (it
+/// could include panics, incorrect results, aborts, memory leaks, or
+/// non-termination) but will not be undefined behavior.
///
/// # Examples
///
/// 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
/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
-/// The behavior resulting from such a logic error is not specified, but will not result in
-/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and
-/// non-termination.
+/// The behavior resulting from such a logic error is not specified (it could include panics,
+/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
+/// behavior.
///
/// [B-Tree]: https://en.wikipedia.org/wiki/B-tree
/// [`Cell`]: core::cell::Cell
/// It is a logic error for an item to be modified in such a way that the item's ordering relative
/// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
-/// The behavior resulting from such a logic error is not specified, but will not result in
-/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and
-/// non-termination.
+/// The behavior resulting from such a logic error is not specified (it could include panics,
+/// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
+/// behavior.
///
/// [`Ord`]: core::cmp::Ord
/// [`Cell`]: core::cell::Cell
//
// 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
///
/// # 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
///
/// Converts a reference to `T` into a reference to an array of length 1 (without copying).
#[stable(feature = "array_from_ref", since = "1.53.0")]
-pub fn from_ref<T>(s: &T) -> &[T; 1] {
+#[rustc_const_unstable(feature = "const_array_from_ref", issue = "90206")]
+pub const fn from_ref<T>(s: &T) -> &[T; 1] {
// SAFETY: Converting `&T` to `&[T; 1]` is sound.
unsafe { &*(s as *const T).cast::<[T; 1]>() }
}
/// Converts a mutable reference to `T` into a mutable reference to an array of length 1 (without copying).
#[stable(feature = "array_from_ref", since = "1.53.0")]
-pub fn from_mut<T>(s: &mut T) -> &mut [T; 1] {
+#[rustc_const_unstable(feature = "const_array_from_ref", issue = "90206")]
+pub const fn from_mut<T>(s: &mut T) -> &mut [T; 1] {
// SAFETY: Converting `&mut T` to `&mut [T; 1]` is sound.
unsafe { &mut *(s as *mut T).cast::<[T; 1]>() }
}
// items.
unsafe { collect_into_array_unchecked(&mut self.iter_mut()) }
}
+
+ /// Divides one array reference into two at an index.
+ ///
+ /// The first will contain all indices from `[0, M)` (excluding
+ /// the index `M` itself) and the second will contain all
+ /// indices from `[M, N)` (excluding the index `N` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `M > N`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let v = [1, 2, 3, 4, 5, 6];
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<0>();
+ /// assert_eq!(left, &[]);
+ /// assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<2>();
+ /// assert_eq!(left, &[1, 2]);
+ /// assert_eq!(right, &[3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<6>();
+ /// assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
+ /// assert_eq!(right, &[]);
+ /// }
+ /// ```
+ #[unstable(
+ feature = "split_array",
+ reason = "return type should have array as 2nd element",
+ issue = "90091"
+ )]
+ #[inline]
+ pub fn split_array_ref<const M: usize>(&self) -> (&[T; M], &[T]) {
+ (&self[..]).split_array_ref::<M>()
+ }
+
+ /// Divides one mutable array reference into two at an index.
+ ///
+ /// The first will contain all indices from `[0, M)` (excluding
+ /// the index `M` itself) and the second will contain all
+ /// indices from `[M, N)` (excluding the index `N` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `M > N`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let mut v = [1, 0, 3, 0, 5, 6];
+ /// let (left, right) = v.split_array_mut::<2>();
+ /// assert_eq!(left, &mut [1, 0][..]);
+ /// assert_eq!(right, &mut [3, 0, 5, 6]);
+ /// left[1] = 2;
+ /// right[1] = 4;
+ /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+ /// ```
+ #[unstable(
+ feature = "split_array",
+ reason = "return type should have array as 2nd element",
+ issue = "90091"
+ )]
+ #[inline]
+ pub fn split_array_mut<const M: usize>(&mut self) -> (&mut [T; M], &mut [T]) {
+ (&mut self[..]).split_array_mut::<M>()
+ }
}
/// Pulls `N` items from `iter` and returns them as an array. If the iterator
#[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.
///
/// 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.
///
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",
#![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(ptr_metadata)]
#![feature(slice_ptr_get)]
#![feature(variant_count)]
+#![feature(const_array_from_ref)]
+#![feature(const_slice_from_ref)]
//
// Language features:
#![feature(abi_unadjusted)]
#![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)]
/// [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"
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
/// Basic usage:
///
/// ```
- /// #![feature(saturating_div)]
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".saturating_div(2), 2);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_div(-1), ", stringify!($SelfT), "::MIN + 1);")]
#[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_div(-1), ", stringify!($SelfT), "::MAX);")]
/// ```
///
/// ```should_panic
- /// #![feature(saturating_div)]
- ///
#[doc = concat!("let _ = 1", stringify!($SelfT), ".saturating_div(0);")]
///
/// ```
- #[unstable(feature = "saturating_div", issue = "87920")]
- #[rustc_const_unstable(feature = "saturating_div", issue = "87920")]
+ #[stable(feature = "saturating_div", since = "1.58.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
}
#[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]
/// Basic usage:
///
/// ```
- /// #![feature(saturating_int_impl, saturating_div)]
+ /// #![feature(saturating_int_impl)]
/// use std::num::Saturating;
///
#[doc = concat!("assert_eq!(Saturating(2", stringify!($t), "), Saturating(5", stringify!($t), ") / Saturating(2));")]
/// ```
///
/// ```should_panic
- /// #![feature(saturating_int_impl, saturating_div)]
+ /// #![feature(saturating_int_impl)]
/// use std::num::Saturating;
///
#[doc = concat!("let _ = Saturating(0", stringify!($t), ") / Saturating(0);")]
/// Basic usage:
///
/// ```
- /// #![feature(saturating_div)]
- ///
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".saturating_div(2), 2);")]
///
/// ```
///
/// ```should_panic
- /// #![feature(saturating_div)]
- ///
#[doc = concat!("let _ = 1", stringify!($SelfT), ".saturating_div(0);")]
///
/// ```
- #[unstable(feature = "saturating_div", issue = "87920")]
- #[rustc_const_unstable(feature = "saturating_div", issue = "87920")]
+ #[stable(feature = "saturating_div", since = "1.58.0")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
// 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 }
};
}
/// ```
///
/// 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);
/// ```
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
#[derive(Debug, Clone, Copy, PartialEq)]
// 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()
}
/// [`rsplit`]: slice::rsplit
/// [slices]: slice
#[stable(feature = "slice_rsplit", since = "1.27.0")]
-#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`?
pub struct RSplit<'a, T: 'a, P>
where
P: FnMut(&T) -> bool,
}
}
+// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
+#[stable(feature = "slice_rsplit", since = "1.27.0")]
+impl<T, P> Clone for RSplit<'_, T, P>
+where
+ P: Clone + FnMut(&T) -> bool,
+{
+ fn clone(&self) -> Self {
+ RSplit { inner: self.inner.clone() }
+ }
+}
+
#[stable(feature = "slice_rsplit", since = "1.27.0")]
impl<'a, T, P> Iterator for RSplit<'a, T, P>
where
/// # 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]
unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) }
}
+ /// Divides one slice into an array and a remainder slice at an index.
+ ///
+ /// The array will contain all indices from `[0, N)` (excluding
+ /// the index `N` itself) and the slice will contain all
+ /// indices from `[N, len)` (excluding the index `len` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let v = &[1, 2, 3, 4, 5, 6][..];
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<0>();
+ /// assert_eq!(left, &[]);
+ /// assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<2>();
+ /// assert_eq!(left, &[1, 2]);
+ /// assert_eq!(right, [3, 4, 5, 6]);
+ /// }
+ ///
+ /// {
+ /// let (left, right) = v.split_array_ref::<6>();
+ /// assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
+ /// assert_eq!(right, []);
+ /// }
+ /// ```
+ #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
+ #[inline]
+ pub fn split_array_ref<const N: usize>(&self) -> (&[T; N], &[T]) {
+ let (a, b) = self.split_at(N);
+ // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at)
+ unsafe { (&*(a.as_ptr() as *const [T; N]), b) }
+ }
+
+ /// Divides one mutable slice into an array and a remainder slice at an index.
+ ///
+ /// The array will contain all indices from `[0, N)` (excluding
+ /// the index `N` itself) and the slice will contain all
+ /// indices from `[N, len)` (excluding the index `len` itself).
+ ///
+ /// # Panics
+ ///
+ /// Panics if `N > len`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(split_array)]
+ ///
+ /// let mut v = &mut [1, 0, 3, 0, 5, 6][..];
+ /// let (left, right) = v.split_array_mut::<2>();
+ /// assert_eq!(left, &mut [1, 0]);
+ /// assert_eq!(right, [3, 0, 5, 6]);
+ /// left[1] = 2;
+ /// right[1] = 4;
+ /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+ /// ```
+ #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
+ #[inline]
+ pub fn split_array_mut<const N: usize>(&mut self) -> (&mut [T; N], &mut [T]) {
+ let (a, b) = self.split_at_mut(N);
+ // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut)
+ unsafe { (&mut *(a.as_mut_ptr() as *mut [T; N]), b) }
+ }
+
/// Returns an iterator over subslices separated by elements that match
/// `pred`. The matched element is not contained in the subslices.
///
//! 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")]
-pub fn from_ref<T>(s: &T) -> &[T] {
+#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
+pub const fn from_ref<T>(s: &T) -> &[T] {
array::from_ref(s)
}
/// Converts a reference to T into a slice of length 1 (without copying).
#[stable(feature = "from_ref", since = "1.28.0")]
-pub fn from_mut<T>(s: &mut T) -> &mut [T] {
+#[rustc_const_unstable(feature = "const_slice_from_ref", issue = "90206")]
+pub const fn from_mut<T>(s: &mut T) -> &mut [T] {
array::from_mut(s)
}
/// 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
///
/// 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;
}
}
/// # Examples
/// ```
/// #![feature(duration_checked_float)]
- ///
/// use std::time::Duration;
///
/// let dur = Duration::try_from_secs_f64(2.7);
} else if nanos >= MAX_NANOS_F64 {
Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
} else if nanos < 0.0 {
- Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+ Err(FromSecsError { kind: FromSecsErrorKind::Negative })
} else {
let nanos = nanos as u128;
Ok(Duration {
/// # Examples
/// ```
/// #![feature(duration_checked_float)]
- ///
/// use std::time::Duration;
///
/// let dur = Duration::try_from_secs_f32(2.7);
} else if nanos >= MAX_NANOS_F32 {
Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
} else if nanos < 0.0 {
- Err(FromSecsError { kind: FromSecsErrorKind::Underflow })
+ Err(FromSecsError { kind: FromSecsErrorKind::Negative })
} else {
let nanos = nanos as u128;
Ok(Duration {
///
/// ```
/// #![feature(duration_checked_float)]
-///
/// use std::time::Duration;
///
/// if let Err(e) = Duration::try_from_secs_f32(-1.0) {
impl FromSecsError {
const fn description(&self) -> &'static str {
match self.kind {
- FromSecsErrorKind::NonFinite => {
- "got non-finite value when converting float to duration"
- }
+ FromSecsErrorKind::NonFinite => "non-finite value when converting float to duration",
FromSecsErrorKind::Overflow => "overflow when converting float to duration",
- FromSecsErrorKind::Underflow => "underflow when converting float to duration",
+ FromSecsErrorKind::Negative => "negative value when converting float to duration",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum FromSecsErrorKind {
- // Value is not a finite value (either infinity or NaN).
+ // Value is not a finite value (either + or - infinity or NaN).
NonFinite,
// Value is too large to store in a `Duration`.
Overflow,
- // Value is less than `0.0`.
- Underflow,
+ // Value is negative.
+ Negative,
}
let value: String = "Hello World!".into();
let arr: &[String; 1] = array::from_ref(&value);
assert_eq!(&[value.clone()], arr);
+
+ const VALUE: &&str = &"Hello World!";
+ const ARR: &[&str; 1] = array::from_ref(VALUE);
+ assert_eq!(&[*VALUE], ARR);
+ assert!(core::ptr::eq(VALUE, &ARR[0]));
}
#[test]
std::panic::set_hook(prev_hook);
result
}
+
+#[test]
+fn array_split_array_mut() {
+ let mut v = [1, 2, 3, 4, 5, 6];
+
+ {
+ let (left, right) = v.split_array_mut::<0>();
+ assert_eq!(left, &mut []);
+ assert_eq!(right, &mut [1, 2, 3, 4, 5, 6]);
+ }
+
+ {
+ let (left, right) = v.split_array_mut::<6>();
+ assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
+ assert_eq!(right, &mut []);
+ }
+}
+
+#[should_panic]
+#[test]
+fn array_split_array_ref_out_of_bounds() {
+ let v = [1, 2, 3, 4, 5, 6];
+
+ v.split_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn array_split_array_mut_out_of_bounds() {
+ let mut v = [1, 2, 3, 4, 5, 6];
+
+ v.split_array_mut::<7>();
+}
#![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(integer_atomics)]
#![feature(int_roundings)]
#![feature(slice_group_by)]
+#![feature(split_array)]
#![feature(trusted_random_access)]
#![feature(unsize)]
#![feature(unzip_option)]
+#![feature(const_array_from_ref)]
+#![feature(const_slice_from_ref)]
#![deny(unsafe_op_in_unsafe_fn)]
extern crate test;
assert_eq!(x.get(), 1);
}
+#[test]
+fn test_const_from_ref() {
+ const VALUE: &i32 = &1;
+ const SLICE: &[i32] = core::slice::from_ref(VALUE);
+
+ assert!(core::ptr::eq(VALUE, &SLICE[0]))
+}
+
#[test]
fn test_slice_fill_with_uninit() {
// This should not UB. See #87891
x.swap(2, 5);
}
}
+
+#[test]
+fn slice_split_array_mut() {
+ let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+ {
+ let (left, right) = v.split_array_mut::<0>();
+ assert_eq!(left, &mut []);
+ assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+ }
+
+ {
+ let (left, right) = v.split_array_mut::<6>();
+ assert_eq!(left, &mut [1, 2, 3, 4, 5, 6]);
+ assert_eq!(right, []);
+ }
+}
+
+#[should_panic]
+#[test]
+fn slice_split_array_ref_out_of_bounds() {
+ let v = &[1, 2, 3, 4, 5, 6][..];
+
+ v.split_array_ref::<7>();
+}
+
+#[should_panic]
+#[test]
+fn slice_split_array_mut_out_of_bounds() {
+ let v = &mut [1, 2, 3, 4, 5, 6][..];
+
+ v.split_array_mut::<7>();
+}
/// determined by the [`Eq`] trait, changes while it is in the set. This is
/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or
/// unsafe code. The behavior resulting from such a logic error is not
-/// specified, but will not result in undefined behavior. This could include
-/// panics, incorrect results, aborts, memory leaks, and non-termination.
+/// specified (it could include panics, incorrect results, aborts, memory
+/// leaks, or non-termination) but will not be undefined behavior.
///
/// # Examples
///
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);
-}
/// }
/// # }
/// ```
+ #[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
#[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).
// "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();
+}
#![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)]
#![feature(ptr_internals)]
#![feature(rustc_attrs)]
#![feature(rustc_private)]
-#![feature(saturating_div)]
#![feature(saturating_int_impl)]
#![feature(slice_concat_ext)]
#![feature(slice_internals)]
fn signal(&self) -> Option<i32>;
/// If the process was terminated by a signal, says whether it dumped core.
- #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
fn core_dumped(&self) -> bool;
/// If the process was stopped by a signal, returns that signal.
///
/// In other words, if `WIFSTOPPED`, this returns `WSTOPSIG`. This is only possible if the status came from
/// a `wait` system call which was passed `WUNTRACED`, and was then converted into an `ExitStatus`.
- #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
fn stopped_signal(&self) -> Option<i32>;
/// Whether the process was continued from a stopped status.
///
/// Ie, `WIFCONTINUED`. This is only possible if the status came from a `wait` system call
/// which was passed `WCONTINUED`, and was then converted into an `ExitStatus`.
- #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
fn continued(&self) -> bool;
/// Returns the underlying raw `wait` status.
///
/// The returned integer is a **wait status, not an exit status**.
- #[unstable(feature = "unix_process_wait_more", issue = "80695")]
+ #[stable(feature = "unix_process_wait_more", since = "1.58.0")]
fn into_raw(self) -> i32;
}
#[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()
}
/// * if `path` has a root but no prefix (e.g., `\windows`), it
/// replaces everything except for the prefix (if any) of `self`.
/// * if `path` has a prefix but no root, it replaces `self`.
+ /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`)
+ /// and `path` is not empty, the new path is normalized: all references
+ /// to `.` and `..` are removed.
///
/// # Examples
///
self.as_mut_vec().truncate(0);
// verbatim paths need . and .. removed
- } else if comps.prefix_verbatim() {
+ } else if comps.prefix_verbatim() && !path.inner.is_empty() {
let mut buf: Vec<_> = comps.collect();
for c in path.components() {
match c {
tp!(r"\\?\A:\x\y", "/foo", r"\\?\A:\foo");
tp!(r"\\?\A:", r"..\foo\.", r"\\?\A:\foo");
tp!(r"\\?\A:\x\y", r".\foo\.", r"\\?\A:\x\y\foo");
+ tp!(r"\\?\A:\x\y", r"", r"\\?\A:\x\y\");
}
}
#[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)
}
}
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(
#[cfg(not(target_vendor = "uwp"))]
fn home_dir_crt() -> Option<PathBuf> {
unsafe {
+ // The magic constant -4 can be used as the token passed to GetUserProfileDirectoryW below
+ // instead of us having to go through these multiple steps to get a token. However this is
+ // not implemented on Windows 7, only Windows 8 and up. When we drop support for Windows 7
+ // we can simplify this code. See #90144 for details.
use crate::sys::handle::Handle;
let me = c::GetCurrentProcess();
+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());
+}
}
}
-/// 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
///
/// global state in order to more accurately query the amount of available
/// parallelism.
///
+/// Resource limits can be changed during the runtime of a program, therefore the value is
+/// not cached and instead recomputed every time this function is called. It should not be
+/// called from hot code.
+///
/// The value returned by this function should be considered a simplified
/// approximation of the actual amount of parallelism available at any given
/// time. To get a more detailed or precise overview of the amount of
}
}
- if self.config.rust_new_symbol_mangling {
+ let use_new_symbol_mangling = match self.config.rust_new_symbol_mangling {
+ Some(setting) => {
+ // If an explicit setting is given, use that
+ setting
+ }
+ None => {
+ if mode == Mode::Std {
+ // The standard library defaults to the legacy scheme
+ false
+ } else {
+ // The compiler and tools default to the new scheme
+ true
+ }
+ }
+ };
+
+ if use_new_symbol_mangling {
rustflags.arg("-Zsymbol-mangling-version=v0");
+ } else {
+ rustflags.arg("-Zsymbol-mangling-version=legacy");
}
// FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
pub rust_verify_llvm_ir: bool,
pub rust_thin_lto_import_instr_limit: Option<u32>,
pub rust_remap_debuginfo: bool,
- pub rust_new_symbol_mangling: bool,
+ pub rust_new_symbol_mangling: Option<bool>,
pub rust_profile_use: Option<String>,
pub rust_profile_generate: Option<String>,
pub llvm_profile_use: Option<String>,
config.rust_run_dsymutil = rust.run_dsymutil.unwrap_or(false);
optimize = rust.optimize;
ignore_git = rust.ignore_git;
- set(&mut config.rust_new_symbol_mangling, rust.new_symbol_mangling);
+ config.rust_new_symbol_mangling = rust.new_symbol_mangling;
set(&mut config.rust_optimize_tests, rust.optimize_tests);
set(&mut config.codegen_tests, rust.codegen_tests);
set(&mut config.rust_rpath, rust.rpath);
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 });
}
}
}
let version = output(cmd.arg("--version"));
let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
- if major >= 10 {
+ if major >= 12 {
return;
}
}
- panic!("\n\nbad LLVM version: {}, need >=10.0\n\n", version)
+ panic!("\n\nbad LLVM version: {}, need >=12.0\n\n", version)
}
fn configure_cmake(
# running with assertions again is not useful
ENV NO_DEBUG_ASSERTIONS=1
ENV NO_LLVM_ASSERTIONS=1
+ENV NO_OVERFLOW_CHECKS=1
# otherwise normally be. We already test libstd with debug assertions in lots of
# other contexts as well
ENV NO_DEBUG_ASSERTIONS=1
+ENV NO_OVERFLOW_CHECKS=1
ENV WASM_TARGETS=wasm32-unknown-unknown
ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_TARGETS \
+++ /dev/null
-FROM ubuntu:18.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
- g++ \
- gcc-multilib \
- make \
- ninja-build \
- file \
- curl \
- ca-certificates \
- python2.7 \
- git \
- cmake \
- sudo \
- gdb \
- llvm-10-tools \
- llvm-10-dev \
- libedit-dev \
- libssl-dev \
- pkg-config \
- zlib1g-dev \
- xz-utils \
- nodejs
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-# using llvm-link-shared due to libffi issues -- see #34486
-ENV RUST_CONFIGURE_ARGS \
- --build=x86_64-unknown-linux-gnu \
- --llvm-root=/usr/lib/llvm-10 \
- --enable-llvm-link-shared \
- --set rust.thin-lto-import-instr-limit=10
-
-ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \
- # Run the `mir-opt` tests again but this time for a 32-bit target.
- # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
- # both 32-bit and 64-bit outputs updated by the PR author, before
- # the PR is approved and tested for merging.
- # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
- # despite having different output on 32-bit vs 64-bit targets.
- python2.7 ../x.py --stage 2 test src/test/mir-opt \
- --host='' --target=i686-unknown-linux-gnu && \
- # Run the UI test suite again, but in `--pass=check` mode
- #
- # This is intended to make sure that both `--pass=check` continues to
- # work.
- #
- python2.7 ../x.py --stage 2 test src/test/ui --pass=check \
- --host='' --target=i686-unknown-linux-gnu && \
- # Run tidy at the very end, after all the other tests.
- python2.7 ../x.py --stage 2 test src/tools/tidy
--- /dev/null
+FROM ubuntu:20.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ g++ \
+ gcc-multilib \
+ make \
+ ninja-build \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ sudo \
+ gdb \
+ llvm-12-tools \
+ llvm-12-dev \
+ libedit-dev \
+ libssl-dev \
+ pkg-config \
+ zlib1g-dev \
+ xz-utils \
+ nodejs
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+ --build=x86_64-unknown-linux-gnu \
+ --llvm-root=/usr/lib/llvm-12 \
+ --enable-llvm-link-shared \
+ --set rust.thin-lto-import-instr-limit=10
+
+ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \
+ # Run the `mir-opt` tests again but this time for a 32-bit target.
+ # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
+ # both 32-bit and 64-bit outputs updated by the PR author, before
+ # the PR is approved and tested for merging.
+ # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
+ # despite having different output on 32-bit vs 64-bit targets.
+ python2.7 ../x.py --stage 2 test src/test/mir-opt \
+ --host='' --target=i686-unknown-linux-gnu && \
+ # Run the UI test suite again, but in `--pass=check` mode
+ #
+ # This is intended to make sure that both `--pass=check` continues to
+ # work.
+ #
+ python2.7 ../x.py --stage 2 test src/test/ui --pass=check \
+ --host='' --target=i686-unknown-linux-gnu && \
+ # Run tidy at the very end, after all the other tests.
+ python2.7 ../x.py --stage 2 test src/tools/tidy
echo "Attempting to download $url"
rm -f /tmp/rustci_docker_cache
set +e
- retry curl -y 30 -Y 10 --connect-timeout 30 -f -L -C - -o /tmp/rustci_docker_cache "$url"
- loaded_images=$(docker load -i /tmp/rustci_docker_cache | sed 's/.* sha/sha/')
+ retry curl --max-time 600 -y 30 -Y 10 --connect-timeout 30 -f -L -C - \
+ -o /tmp/rustci_docker_cache "$url"
+ echo "Loading images into docker"
+ # docker load sometimes hangs in the CI, so time out after 10 minutes with TERM,
+ # KILL after 12 minutes
+ loaded_images=$(/usr/bin/timeout -k 720 600 docker load -i /tmp/rustci_docker_cache \
+ | sed 's/.* sha/sha/')
set -e
echo "Downloaded containers:\n$loaded_images"
fi
- name: mingw-check
<<: *job-linux-xl
- - name: x86_64-gnu-llvm-10
+ - name: x86_64-gnu-llvm-12
<<: *job-linux-xl
- name: x86_64-gnu-tools
- name: x86_64-gnu-distcheck
<<: *job-linux-xl
- - name: x86_64-gnu-llvm-10
+ - name: x86_64-gnu-llvm-12
env:
RUST_BACKTRACE: 1
<<: *job-linux-xl
# macOS Builders #
####################
+ # Only generate documentation for x86_64-apple-darwin, not other
+ # tier 2 targets produced by this builder.
- name: dist-x86_64-apple
env:
- SCRIPT: ./x.py dist
+ 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
+ NO_OVERFLOW_CHECKS: 1
DIST_REQUIRE_ALL_TOOLS: 1
<<: *job-macos-xl
MACOSX_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
<<: *job-macos-xl
- name: x86_64-apple
MACOSX_STD_DEPLOYMENT_TARGET: 10.7
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
<<: *job-macos-xl
# This target only needs to support 11.0 and up as nothing else supports the hardware
MACOSX_STD_DEPLOYMENT_TARGET: 11.0
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
+ NO_OVERFLOW_CHECKS: 1
DIST_REQUIRE_ALL_TOOLS: 1
# Corresponds to 16K page size
#
strategy:
matrix:
include:
- - *dist-x86_64-linux
+ - &dist-x86_64-linux
+ name: dist-x86_64-linux
+ <<: *job-linux-xl
master:
name: master
PYTHON="python2"
fi
-if ! isCI || isCiBranch auto || isCiBranch beta; then
+if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests"
fi
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-debug-assertions"
fi
+ # Same for overflow checks
+ if [ "$NO_OVERFLOW_CHECKS" = "" ]; then
+ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-overflow-checks"
+ fi
+
# In general we always want to run tests with LLVM assertions enabled, but not
# all platforms currently support that, so we have an option to disable.
if [ "$NO_LLVM_ASSERTIONS" = "" ]; then
-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
<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>.
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`.
* static
* typedef
2. If one of the previously listed items has a code example, then it'll be counted.
+
+### `--with-examples`: include examples of uses of items as documentation
+
+This option, combined with `--scrape-examples-target-crate` and
+`--scrape-examples-output-path`, is used to implement the functionality in [RFC
+#3123](https://github.com/rust-lang/rfcs/pull/3123). Uses of an item (currently
+functions / call-sites) are found in a crate and its reverse-dependencies, and
+then the uses are included as documentation for that item. This feature is
+intended to be used via `cargo doc --scrape-examples`, but the rustdoc-only
+workflow looks like:
+
+```bash
+$ rustdoc examples/ex.rs -Z unstable-options \
+ --extern foobar=target/deps/libfoobar.rmeta \
+ --scrape-examples-target-crate foobar \
+ --scrape-examples-output-path output.calls
+$ rustdoc src/lib.rs -Z unstable-options --with-examples output.calls
+```
+
+First, the library must be checked to generate an `rmeta`. Then a
+reverse-dependency like `examples/ex.rs` is given to rustdoc with the target
+crate being documented (`foobar`) and a path to output the calls
+(`output.calls`). Then, the generated calls file can be passed via
+`--with-examples` to the subsequent documentation of `foobar`.
--- /dev/null
+# `location-detail`
+
+The tracking issue for this feature is: [#70580](https://github.com/rust-lang/rust/issues/70580).
+
+------------------------
+
+Option `-Z location-detail=val` controls what location details are tracked when
+using `caller_location`. This allows users to control what location details
+are printed as part of panic messages, by allowing them to exclude any combination
+of filenames, line numbers, and column numbers. This option is intended to provide
+users with a way to mitigate the size impact of `#[track_caller]`.
+
+This option supports a comma separated list of location details to be included. Valid options
+within this list are:
+
+- `file` - the filename of the panic will be included in the panic output
+- `line` - the source line of the panic will be included in the panic output
+- `column` - the source column of the panic will be included in the panic output
+
+Any combination of these three options are supported. If this option is not specified,
+all three are included by default.
+
+An example of a panic output when using `-Z location-detail=line`:
+```text
+panicked at 'Process blink had a fault', <redacted>:323:0
+```
+
+The code size savings from this option are two-fold. First, the `&'static str` values
+for each path to a file containing a panic are removed from the binary. For projects
+with deep directory structures and many files with panics, this can add up. This category
+of savings can only be realized by excluding filenames from the panic output. Second,
+savings can be realized by allowing multiple panics to be fused into a single panicking
+branch. It is often the case that within a single file, multiple panics with the same
+panic message exist -- e.g. two calls to `Option::unwrap()` in a single line, or
+two calls to `Result::expect()` on adjacent lines. If column and line information
+are included in the `Location` struct passed to the panic handler, these branches cannot
+be fused, as the output is different depending on which panic occurs. However if line
+and column information is identical for all panics, these branches can be fused, which
+can lead to substantial code size savings, especially for small embedded binaries with
+many panics.
+
+The savings from this option are amplified when combined with the use of `-Zbuild-std`, as
+otherwise paths for panics within the standard library are still included in your binary.
--- /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.
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"
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))
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol};
-use crate::clean::{
- self, utils, Attributes, AttributesExt, GetDefId, ItemId, NestedAttributesExt, Type,
-};
+use crate::clean::{self, utils, Attributes, AttributesExt, ItemId, NestedAttributesExt, Type};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
}
}
-/// 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;
}
}
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,
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.lt_substs.get(&node_id).cloned() {
+ return lt;
}
- _ => {}
}
Lifetime(self.name.ident().name)
}
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_,
}
.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(),
}
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))
});
}
TyMethodItem(t)
}
- hir::TraitItemKind::Type(ref bounds, ref default) => {
+ hir::TraitItemKind::Type(bounds, ref default) => {
AssocTypeItem(bounds.clean(cx), default.clean(cx))
}
};
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) {
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),
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.clean(cx)),
TyKind::OpaqueDef(item_id, _) => {
let item = cx.tcx.hir().item(item_id);
if let hir::ItemKind::OpaqueTy(ref ty) = item.kind {
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()).collect::<Vec<_>>().clean(cx)),
ty::Projection(ref data) => data.clean(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))
}
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,
});
impl Clean<Item> for (&hir::ForeignItem<'_>, Option<Symbol>) {
fn clean(&self, cx: &mut DocContext<'_>) -> Item {
let (item, renamed) = self;
- cx.with_param_env(item.def_id.to_def_id(), |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))
+ (generics.clean(cx), (&*decl, &names[..]).clean(cx))
});
ForeignFunctionItem(Function {
decl,
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() }
}
}
.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)| {
{
*span
} else {
- self.def_id.as_def_id().map(|did| rustc_span(did, tcx)).unwrap_or_else(|| Span::dummy())
+ 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() {
// #[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>,
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());
/// 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.
use crate::html::static_files;
use crate::opts;
use crate::passes::{self, Condition, DefaultPassOption};
+use crate::scrape_examples::{AllCallLocations, ScrapeExamplesOptions};
use crate::theme;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
crate json_unused_externs: bool,
/// Whether to skip capturing stdout and stderr of tests.
crate nocapture: bool,
+
+ /// Configuration for scraping examples from the current crate. If this option is Some(..) then
+ /// the compiler will scrape examples and not generate documentation.
+ crate scrape_examples_options: Option<ScrapeExamplesOptions>,
}
impl fmt::Debug for Options {
.field("run_check", &self.run_check)
.field("no_run", &self.no_run)
.field("nocapture", &self.nocapture)
+ .field("scrape_examples_options", &self.scrape_examples_options)
.finish()
}
}
crate emit: Vec<EmitType>,
/// If `true`, HTML source pages will generate links for items to their definition.
crate generate_link_to_definition: bool,
+ crate call_locations: AllCallLocations,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// 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,
return Err(1);
}
+ let scrape_examples_options = ScrapeExamplesOptions::new(&matches, &diag)?;
+ let with_examples = matches.opt_strs("with-examples");
+ let call_locations = crate::scrape_examples::load_call_locations(with_examples, &diag)?;
+
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
Ok(Options {
),
emit,
generate_link_to_definition,
+ call_locations,
},
crate_name,
output_format,
json_unused_externs,
+ scrape_examples_options,
})
}
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 {
_ => 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)));
}
}
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(())
}
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,
.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;
}
}
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;
}
// 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 {
ItemType::ProcAttribute => "attr",
ItemType::ProcDerive => "derive",
ItemType::TraitAlias => "traitalias",
+ ItemType::Generic => "generic",
}
}
}
/// 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)
}
}
}
use std::collections::VecDeque;
use std::fmt::{Display, Write};
+use rustc_data_structures::fx::FxHashMap;
use rustc_lexer::{LiteralKind, TokenKind};
use rustc_span::edition::Edition;
use rustc_span::symbol::Symbol;
crate root_path: &'c str,
}
+/// Decorations are represented as a map from CSS class to vector of character ranges.
+/// Each range will be wrapped in a span with that class.
+crate struct DecorationInfo(crate FxHashMap<&'static str, Vec<(u32, u32)>>);
+
/// Highlights `src`, returning the HTML output.
crate fn render_with_highlighting(
src: &str,
edition: Edition,
extra_content: Option<Buffer>,
context_info: Option<ContextInfo<'_, '_, '_>>,
+ decoration_info: Option<DecorationInfo>,
) {
debug!("highlighting: ================\n{}\n==============", src);
if let Some((edition_info, class)) = tooltip {
}
write_header(out, class, extra_content);
- write_code(out, &src, edition, context_info);
+ write_code(out, src, edition, context_info, decoration_info);
write_footer(out, playground_button);
}
src: &str,
edition: Edition,
context_info: Option<ContextInfo<'_, '_, '_>>,
+ decoration_info: Option<DecorationInfo>,
) {
// This replace allows to fix how the code source with DOS backline characters is displayed.
let src = src.replace("\r\n", "\n");
- Classifier::new(&src, edition, context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP))
- .highlight(&mut |highlight| {
- match highlight {
- Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
- Highlight::EnterSpan { class } => enter_span(out, class),
- Highlight::ExitSpan => exit_span(out),
- };
- });
+ Classifier::new(
+ &src,
+ edition,
+ context_info.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
+ decoration_info,
+ )
+ .highlight(&mut |highlight| {
+ match highlight {
+ Highlight::Token { text, class } => string(out, Escape(text), class, &context_info),
+ Highlight::EnterSpan { class } => enter_span(out, class),
+ Highlight::ExitSpan => exit_span(out),
+ };
+ });
}
fn write_footer(out: &mut Buffer, playground_button: Option<&str>) {
PreludeTy,
PreludeVal,
QuestionMark,
+ Decoration(&'static str),
}
impl Class {
Class::PreludeTy => "prelude-ty",
Class::PreludeVal => "prelude-val",
Class::QuestionMark => "question-mark",
+ Class::Decoration(kind) => kind,
}
}
}
}
+/// Custom spans inserted into the source. Eg --scrape-examples uses this to highlight function calls
+struct Decorations {
+ starts: Vec<(u32, &'static str)>,
+ ends: Vec<u32>,
+}
+
+impl Decorations {
+ fn new(info: DecorationInfo) -> Self {
+ let (starts, ends) = info
+ .0
+ .into_iter()
+ .map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
+ .flatten()
+ .unzip();
+ Decorations { starts, ends }
+ }
+}
+
/// Processes program tokens, classifying strings of text by highlighting
/// category (`Class`).
struct Classifier<'a> {
byte_pos: u32,
file_span: Span,
src: &'a str,
+ decorations: Option<Decorations>,
}
impl<'a> Classifier<'a> {
/// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
/// file span which will be used later on by the `span_correspondance_map`.
- fn new(src: &str, edition: Edition, file_span: Span) -> Classifier<'_> {
+ fn new(
+ src: &str,
+ edition: Edition,
+ file_span: Span,
+ decoration_info: Option<DecorationInfo>,
+ ) -> Classifier<'_> {
let tokens = PeekIter::new(TokenIter { src });
+ let decorations = decoration_info.map(Decorations::new);
Classifier {
tokens,
in_attribute: false,
byte_pos: 0,
file_span,
src,
+ decorations,
}
}
/// token is used.
fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) {
loop {
+ if let Some(decs) = self.decorations.as_mut() {
+ let byte_pos = self.byte_pos;
+ let n_starts = decs.starts.iter().filter(|(i, _)| byte_pos >= *i).count();
+ for (_, kind) in decs.starts.drain(0..n_starts) {
+ sink(Highlight::EnterSpan { class: Class::Decoration(kind) });
+ }
+
+ let n_ends = decs.ends.iter().filter(|i| byte_pos >= **i).count();
+ for _ in decs.ends.drain(0..n_ends) {
+ sink(Highlight::ExitSpan);
+ }
+ }
+
if self
.tokens
.peek()
// 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,
},
// https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338
match href {
LinkFromSrc::Local(span) => context
- .href_from_span(*span)
+ .href_from_span(*span, true)
.map(|s| format!("{}{}", context_info.root_path, s)),
LinkFromSrc::External(def_id) => {
format::href_with_root_path(*def_id, context, Some(context_info.root_path))
.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),
)
--- /dev/null
+<span class="example"><span class="kw">let</span> <span class="ident">x</span> <span class="op">=</span> <span class="number">1</span>;</span>
+<span class="kw">let</span> <span class="ident">y</span> <span class="op">=</span> <span class="number">2</span>;
\ No newline at end of file
<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>
-use super::write_code;
+use super::{write_code, DecorationInfo};
use crate::html::format::Buffer;
use expect_test::expect_file;
+use rustc_data_structures::fx::FxHashMap;
use rustc_span::create_default_session_globals_then;
use rustc_span::edition::Edition;
let src = include_str!("fixtures/sample.rs");
let html = {
let mut out = Buffer::new();
- write_code(&mut out, src, Edition::Edition2018, None);
+ write_code(&mut out, src, Edition::Edition2018, None, None);
format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
};
expect_file!["fixtures/sample.html"].assert_eq(&html);
println!(\"foo\");\r\n\
}\r\n";
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None);
+ write_code(&mut html, src, Edition::Edition2018, None, None);
expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
});
}
let y = Self::whatever;";
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None);
+ write_code(&mut html, src, Edition::Edition2018, None, None);
expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
});
}
create_default_session_globals_then(|| {
let src = include_str!("fixtures/union.rs");
let mut html = Buffer::new();
- write_code(&mut html, src, Edition::Edition2018, None);
+ write_code(&mut html, src, Edition::Edition2018, None, None);
expect_file!["fixtures/union.html"].assert_eq(&html.into_inner());
});
}
+
+#[test]
+fn test_decorations() {
+ create_default_session_globals_then(|| {
+ let src = "let x = 1;
+let y = 2;";
+ let mut decorations = FxHashMap::default();
+ decorations.insert("example", vec![(0, 10)]);
+
+ let mut html = Buffer::new();
+ write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations)));
+ expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
+ });
+}
/// If false, the `select` element to have search filtering by crates on rendered docs
/// won't be generated.
crate generate_search_filter: bool,
+ /// If true, then scrape-examples.js will be included in the output HTML file
+ crate scrape_examples_extension: bool,
}
#[derive(Serialize)]
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!(
edition,
None,
None,
+ None,
);
Some(Event::Html(s.into_inner().into()))
}
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) {
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::format::Buffer;
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> {
crate span_correspondance_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
/// The [`Cache`] used during rendering.
crate cache: Cache,
+
+ crate call_locations: AllCallLocations,
}
impl SharedContext<'_> {
}
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() {
/// may happen, for example, with externally inlined items where the source
/// of their crate documentation isn't known.
pub(super) fn src_href(&self, item: &clean::Item) -> Option<String> {
- self.href_from_span(item.span(self.tcx()))
+ self.href_from_span(item.span(self.tcx()), true)
}
- crate fn href_from_span(&self, span: clean::Span) -> Option<String> {
+ crate fn href_from_span(&self, span: clean::Span, with_lines: bool) -> Option<String> {
if span.is_dummy() {
return None;
}
(&*symbol, &path)
};
- let loline = span.lo(self.sess()).line;
- let hiline = span.hi(self.sess()).line;
- let lines =
- if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) };
+ let anchor = if with_lines {
+ let loline = span.lo(self.sess()).line;
+ let hiline = span.hi(self.sess()).line;
+ format!(
+ "#{}",
+ if loline == hiline {
+ loline.to_string()
+ } else {
+ format!("{}-{}", loline, hiline)
+ }
+ )
+ } else {
+ "".to_string()
+ };
Some(format!(
- "{root}src/{krate}/{path}#{lines}",
+ "{root}src/{krate}/{path}{anchor}",
root = Escape(&root),
krate = krate,
path = path,
- lines = lines
+ anchor = anchor
))
}
}
generate_redirect_map,
show_type_layout,
generate_link_to_definition,
+ call_locations,
..
} = options;
krate: krate.name.to_string(),
css_file_extension: extension_css,
generate_search_filter,
+ scrape_examples_extension: !call_locations.is_empty(),
};
let mut issue_tracker_base_url = None;
let mut include_sources = true;
templates,
span_correspondance_map: matches,
cache,
+ call_locations,
};
// Add the default themes to the `Vec` of stylepaths
dst,
render_redirect_pages: false,
id_map: RefCell::new(id_map),
+ deref_id_map: RefCell::new(FxHashMap::default()),
shared: Rc::new(scx),
include_sources,
};
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,
use std::collections::VecDeque;
use std::default::Default;
use std::fmt;
+use std::fs;
+use std::iter::Peekable;
use std::path::PathBuf;
use std::str;
use std::string::ToString;
use rustc_ast_pretty::pprust;
use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::DefId;
use rustc_hir::Mutability;
use rustc_middle::middle::stability;
use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::{
+ symbol::{kw, sym, Symbol},
+ BytePos, FileName, RealFileName,
+};
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;
href, print_abi_with_space, print_constness_with_space, print_default_space,
print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace,
};
+use crate::html::highlight;
use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
+use crate::html::sources;
+use crate::scrape_examples::CallData;
+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 {
render_markdown(w, cx, &s, item.links(cx), heading_offset);
}
}
+
+ let kind = match &*item.kind {
+ clean::ItemKind::StrippedItem(box kind) | kind => kind,
+ };
+
+ if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind {
+ render_call_locations(w, cx, item);
+ }
}
/// Add extra information about an item such as:
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);
let (blanket_impl, concrete): (Vec<&&Impl>, _) =
concrete.into_iter().partition(|t| t.inner_impl().blanket_impl.is_some());
- 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>| {
}
}
-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!(),
}
}
}
out
}
+
+const MAX_FULL_EXAMPLES: usize = 5;
+const NUM_VISIBLE_LINES: usize = 10;
+
+/// Generates the HTML for example call locations generated via the --scrape-examples flag.
+fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
+ let tcx = cx.tcx();
+ let def_id = item.def_id.expect_def_id();
+ let key = tcx.def_path_hash(def_id);
+ let call_locations = match cx.shared.call_locations.get(&key) {
+ Some(call_locations) => call_locations,
+ _ => {
+ return;
+ }
+ };
+
+ // Generate a unique ID so users can link to this section for a given method
+ let id = cx.id_map.borrow_mut().derive("scraped-examples");
+ write!(
+ w,
+ "<div class=\"docblock scraped-example-list\">\
+ <span></span>\
+ <h5 id=\"{id}\" class=\"section-header\">\
+ <a href=\"#{id}\">Examples found in repository</a>\
+ </h5>",
+ id = id
+ );
+
+ // 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) {
+ Ok(contents) => contents,
+ Err(err) => {
+ let span = item.span(tcx).inner();
+ tcx.sess
+ .span_err(span, &format!("failed to read file {}: {}", path.display(), err));
+ return false;
+ }
+ };
+
+ // To reduce file sizes, we only want to embed the source code needed to understand the example, not
+ // the entire file. So we find the smallest byte range that covers all items enclosing examples.
+ assert!(!call_data.locations.is_empty());
+ let min_loc =
+ call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
+ let byte_min = min_loc.enclosing_item.byte_span.0;
+ let line_min = min_loc.enclosing_item.line_span.0;
+ let max_loc =
+ call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap();
+ let byte_max = max_loc.enclosing_item.byte_span.1;
+ let line_max = max_loc.enclosing_item.line_span.1;
+
+ // The output code is limited to that byte range.
+ let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
+
+ // The call locations need to be updated to reflect that the size of the program has changed.
+ // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
+ let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
+ .locations
+ .iter()
+ .map(|loc| {
+ let (byte_lo, byte_hi) = loc.call_expr.byte_span;
+ 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);
+
+ (byte_range, (line_range, line_url, line_title))
+ })
+ .unzip();
+
+ let (_, init_url, init_title) = &line_ranges[0];
+ let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
+ let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
+
+ write!(
+ w,
+ "<div class=\"scraped-example {expanded_cls}\" data-locs=\"{locations}\">\
+ <div class=\"scraped-example-title\">\
+ {name} (<a href=\"{url}\">{title}</a>)\
+ </div>\
+ <div class=\"code-wrapper\">",
+ expanded_cls = if needs_expansion { "" } else { "expanded" },
+ name = call_data.display_name,
+ url = init_url,
+ title = init_title,
+ // The locations are encoded as a data attribute, so they can be read
+ // later by the JS for interactions.
+ locations = Escape(&locations_encoded)
+ );
+
+ if line_ranges.len() > 1 {
+ write!(w, r#"<span class="prev">≺</span> <span class="next">≻</span>"#);
+ }
+
+ if needs_expansion {
+ write!(w, r#"<span class="expand">↕</span>"#);
+ }
+
+ // Look for the example file in the source map if it exists, otherwise return a dummy span
+ let file_span = (|| {
+ let source_map = tcx.sess.source_map();
+ let crate_src = tcx.sess.local_crate_source_file.as_ref()?;
+ let abs_crate_src = crate_src.canonicalize().ok()?;
+ let crate_root = abs_crate_src.parent()?.parent()?;
+ let rel_path = path.strip_prefix(crate_root).ok()?;
+ let files = source_map.files();
+ let file = files.iter().find(|file| match &file.name {
+ FileName::Real(RealFileName::LocalPath(other_path)) => rel_path == other_path,
+ _ => false,
+ })?;
+ Some(rustc_span::Span::with_root_ctxt(
+ file.start_pos + BytePos(byte_min),
+ file.start_pos + BytePos(byte_max),
+ ))
+ })()
+ .unwrap_or(rustc_span::DUMMY_SP);
+
+ // The root path is the inverse of Context::current
+ let root_path = vec!["../"; cx.current.len() - 1].join("");
+
+ let mut decoration_info = FxHashMap::default();
+ decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
+ decoration_info.insert("highlight", byte_ranges);
+
+ sources::print_src(
+ w,
+ contents_subset,
+ call_data.edition,
+ file_span,
+ cx,
+ &root_path,
+ Some(highlight::DecorationInfo(decoration_info)),
+ sources::SourceContext::Embedded { offset: line_min },
+ );
+ write!(w, "</div></div>");
+
+ true
+ };
+
+ // The call locations are output in sequence, so that sequence needs to be determined.
+ // Ideally the most "relevant" examples would be shown first, but there's no general algorithm
+ // for determining relevance. Instead, we prefer the smallest examples being likely the easiest to
+ // understand at a glance.
+ let ordered_locations = {
+ let sort_criterion = |(_, call_data): &(_, &CallData)| {
+ // Use the first location because that's what the user will see initially
+ let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
+ hi - lo
+ };
+
+ let mut locs = call_locations.into_iter().collect::<Vec<_>>();
+ locs.sort_by_key(sort_criterion);
+ locs
+ };
+
+ let mut it = ordered_locations.into_iter().peekable();
+
+ // An example may fail to write if its source can't be read for some reason, so this method
+ // continues iterating until a write suceeds
+ let write_and_skip_failure = |w: &mut Buffer, it: &mut Peekable<_>| {
+ while let Some(example) = it.next() {
+ if write_example(&mut *w, example) {
+ break;
+ }
+ }
+ };
+
+ // Write just one example that's visible by default in the method's description.
+ write_and_skip_failure(w, &mut it);
+
+ // Then add the remaining examples in a hidden section.
+ if it.peek().is_some() {
+ write!(
+ w,
+ "<details class=\"rustdoc-toggle more-examples-toggle\">\
+ <summary class=\"hideme\">\
+ <span>More examples</span>\
+ </summary>\
+ <div class=\"more-scraped-examples\">\
+ <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
+ <div class=\"more-scraped-examples-inner\">"
+ );
+
+ // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
+ // make the page arbitrarily huge!
+ for _ in 0..MAX_FULL_EXAMPLES {
+ write_and_skip_failure(w, &mut it);
+ }
+
+ // For the remaining examples, generate a <ul> containing links to the source files.
+ 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)| {
+ write!(
+ w,
+ r#"<li><a href="{root}{url}">{name}</a></li>"#,
+ root = cx.root_path(),
+ url = call_data.url,
+ name = call_data.display_name
+ );
+ });
+ write!(w, "</ul></div>");
+ }
+
+ write!(w, "</div></div></details>");
+ }
+
+ write!(w, "</div>");
+}
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>) =
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!(),
}
it.span(cx.tcx()).inner().edition(),
None,
None,
+ None,
);
});
document(w, cx, it, None, HeadingOffset::H2)
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);
}
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))
})?
)?;
}
+ if cx.shared.layout.scrape_examples_extension {
+ cx.write_minify(
+ SharedResource::InvocationSpecific { basename: "scrape-examples.js" },
+ static_files::SCRAPE_EXAMPLES_JS,
+ options.enable_minification,
+ &options.emit,
+ )?;
+ }
+
if let Some(ref css) = cx.shared.layout.css_file_extension {
let buffer = try_err!(fs::read_to_string(css), css);
// This varies based on the invocation, so it can't go through the write_minify wrapper.
}
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('/');
});
};
// 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();
&page,
"",
|buf: &mut _| {
- print_src(buf, contents, self.cx.shared.edition(), file_span, &self.cx, &root_path)
+ print_src(
+ buf,
+ contents,
+ self.cx.shared.edition(),
+ file_span,
+ self.cx,
+ &root_path,
+ None,
+ SourceContext::Standalone,
+ )
},
&self.cx.shared.style_files,
);
}
}
+crate enum SourceContext {
+ Standalone,
+ Embedded { offset: usize },
+}
+
/// Wrapper struct to render the source code of a file. This will do things like
/// adding line numbers to the left-hand side.
-fn print_src(
+crate fn print_src(
buf: &mut Buffer,
s: &str,
edition: Edition,
file_span: rustc_span::Span,
context: &Context<'_>,
root_path: &str,
+ decoration_info: Option<highlight::DecorationInfo>,
+ source_context: SourceContext,
) {
let lines = s.lines().count();
let mut line_numbers = Buffer::empty_from(buf);
}
line_numbers.write_str("<pre class=\"line-numbers\">");
for i in 1..=lines {
- writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols);
+ match source_context {
+ SourceContext::Standalone => {
+ writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols)
+ }
+ SourceContext::Embedded { offset } => {
+ writeln!(line_numbers, "<span>{0:1$}</span>", i + offset, cols)
+ }
+ }
}
line_numbers.write_str("</pre>");
highlight::render_with_highlighting(
edition,
Some(line_numbers),
Some(highlight::ContextInfo { context, file_span, root_path }),
+ decoration_info,
);
}
/* 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 {
border-bottom: 1px solid;
}
-h3.code-header, h4.code-header {
+h3.code-header {
+ font-size: 1.1em;
+}
+h4.code-header {
font-size: 1em;
+}
+h3.code-header, h4.code-header {
font-weight: 600;
- border: none;
+ border-bottom-style: none;
padding: 0;
margin: 0;
}
margin-bottom: 10px;
position: relative;
}
-.impl, .method.trait-impl,
-.type.trait-impl,
-.associatedconstant.trait-impl,
-.associatedtype.trait-impl {
- padding-left: 15px;
-}
div.impl-items > div {
padding-left: 0;
.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 {
overflow-x: auto;
}
+.rustdoc:not(.source) .example-wrap > pre.line-numbers {
+ width: auto;
+ overflow-x: visible;
+}
+
.rustdoc .example-wrap > pre {
margin: 0;
}
position: relative;
}
-.docblock > * {
+.docblock > :not(.information) {
max-width: 100%;
overflow-x: auto;
}
left: -19px;
}
-.content .impl-items .method, .content .impl-items > .type, .impl-items > .associatedconstant,
-.impl-items > .associatedtype, .content .impl-items details > summary > .type,
-.impl-items details > summary > .associatedconstant,
-.impl-items details > summary > .associatedtype {
- margin-left: 20px;
-}
-
.content .impl-items .docblock, .content .impl-items .item-info {
margin-bottom: .6em;
}
.anchor {
display: none;
position: absolute;
- left: 0;
+ left: -0.5em;
background: none !important;
}
.anchor.field {
details.rustdoc-toggle > summary:not(.hideme)::before {
position: absolute;
- left: -23px;
+ left: -24px;
top: 3px;
}
.impl-items > details.rustdoc-toggle > summary:not(.hideme)::before,
.undocumented > details.rustdoc-toggle > summary:not(.hideme)::before {
position: absolute;
- left: -2px;
+ left: -24px;
}
/* When a "hideme" summary is open and the "Expand description" or "Show
overflow-wrap: anywhere;
}
}
+
+
+/* Begin: styles for --scrape-examples feature */
+
+.scraped-example-title {
+ font-family: 'Fira Sans';
+}
+
+.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
+ overflow: hidden;
+ max-height: 240px;
+}
+
+.scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust {
+ overflow-y: hidden;
+ max-height: 240px;
+ padding-bottom: 0;
+}
+
+.scraped-example .code-wrapper .prev {
+ position: absolute;
+ top: 0.25em;
+ right: 2.25em;
+ z-index: 100;
+ cursor: pointer;
+}
+
+.scraped-example .code-wrapper .next {
+ position: absolute;
+ top: 0.25em;
+ right: 1.25em;
+ z-index: 100;
+ cursor: pointer;
+}
+
+.scraped-example .code-wrapper .expand {
+ position: absolute;
+ top: 0.25em;
+ right: 0.25em;
+ z-index: 100;
+ cursor: pointer;
+}
+
+.scraped-example .code-wrapper {
+ position: relative;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ width: 100%;
+}
+
+.scraped-example:not(.expanded) .code-wrapper:before {
+ content: " ";
+ width: 100%;
+ height: 5px;
+ position: absolute;
+ z-index: 100;
+ top: 0;
+ background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+
+.scraped-example:not(.expanded) .code-wrapper:after {
+ content: " ";
+ width: 100%;
+ height: 5px;
+ position: absolute;
+ z-index: 100;
+ bottom: 0;
+ background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
+}
+
+.scraped-example:not(.expanded) .code-wrapper {
+ overflow: hidden;
+ max-height: 240px;
+}
+
+.scraped-example .code-wrapper .line-numbers {
+ margin: 0;
+ padding: 14px 0;
+}
+
+.scraped-example .code-wrapper .line-numbers span {
+ padding: 0 14px;
+}
+
+.scraped-example .code-wrapper .example-wrap {
+ flex: 1;
+ overflow-x: auto;
+ overflow-y: hidden;
+ margin-bottom: 0;
+}
+
+.scraped-example .code-wrapper .example-wrap pre.rust {
+ overflow-x: inherit;
+ width: inherit;
+ overflow-y: hidden;
+}
+
+.scraped-example .example-wrap .rust span.highlight {
+ background: #fcffd6;
+}
+
+.scraped-example .example-wrap .rust span.highlight.focus {
+ background: #f6fdb0;
+}
+
+.more-examples-toggle {
+ margin-top: 10px;
+}
+
+.more-examples-toggle summary {
+ color: #999;
+ font-family: 'Fira Sans';
+}
+
+.more-scraped-examples {
+ margin-left: 25px;
+ display: flex;
+ flex-direction: row;
+ width: calc(100% - 25px);
+}
+
+.more-scraped-examples-inner {
+ /* 20px is width of toggle-line + toggle-line-inner */
+ width: calc(100% - 20px);
+}
+
+.toggle-line {
+ align-self: stretch;
+ margin-right: 10px;
+ margin-top: 5px;
+ padding: 0 4px;
+ cursor: pointer;
+}
+
+.toggle-line:hover .toggle-line-inner {
+ background: #aaa;
+}
+
+.toggle-line-inner {
+ min-width: 2px;
+ background: #ddd;
+ height: 100%;
+}
+
+.more-scraped-examples .scraped-example {
+ margin-bottom: 20px;
+}
+
+.more-scraped-examples .scraped-example:last-child {
+ margin-bottom: 0;
+}
+
+.example-links a {
+ margin-top: 20px;
+ font-family: 'Fira Sans';
+}
+
+.example-links ul {
+ margin-bottom: 0;
+}
+
+/* End: styles for --scrape-examples feature */
input:checked + .slider {
background-color: #ffb454 !important;
}
+
+.scraped-example .example-wrap .rust span.highlight {
+ background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+ background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+ background: linear-gradient(to bottom, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+ background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
+}
+.toggle-line-inner {
+ background: #616161;
+}
+.toggle-line:hover .toggle-line-inner {
+ background: ##898989;
+}
.setting-line > .title {
border-bottom-color: #ddd;
}
+
+.scraped-example .example-wrap .rust span.highlight {
+ background: rgb(91, 59, 1);
+}
+.scraped-example .example-wrap .rust span.highlight.focus {
+ background: rgb(124, 75, 15);
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
+ background: linear-gradient(to bottom, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.scraped-example:not(.expanded) .code-wrapper:after {
+ background: linear-gradient(to top, rgba(53, 53, 53, 1), rgba(53, 53, 53, 0));
+}
+.toggle-line-inner {
+ background: #616161;
+}
+.toggle-line:hover .toggle-line-inner {
+ background: ##898989;
+}
--- /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.
--- /dev/null
+/* global addClass, hasClass, removeClass, onEach */
+
+(function () {
+ // Scroll code block to put the given code location in the middle of the viewer
+ function scrollToLoc(elt, loc) {
+ var wrapper = elt.querySelector(".code-wrapper");
+ var halfHeight = wrapper.offsetHeight / 2;
+ var lines = elt.querySelector('.line-numbers');
+ var offsetMid = (lines.children[loc[0]].offsetTop
+ + lines.children[loc[1]].offsetTop) / 2;
+ var scrollOffset = offsetMid - halfHeight;
+ lines.scrollTo(0, scrollOffset);
+ elt.querySelector(".rust").scrollTo(0, scrollOffset);
+ }
+
+ function updateScrapedExample(example) {
+ var locs = JSON.parse(example.attributes.getNamedItem("data-locs").textContent);
+ var locIndex = 0;
+ var highlights = example.querySelectorAll('.highlight');
+ var link = example.querySelector('.scraped-example-title a');
+
+ if (locs.length > 1) {
+ // Toggle through list of examples in a given file
+ var onChangeLoc = function(changeIndex) {
+ removeClass(highlights[locIndex], 'focus');
+ changeIndex();
+ scrollToLoc(example, locs[locIndex][0]);
+ addClass(highlights[locIndex], 'focus');
+
+ var url = locs[locIndex][1];
+ var title = locs[locIndex][2];
+
+ link.href = url;
+ link.innerHTML = title;
+ };
+
+ example.querySelector('.prev')
+ .addEventListener('click', function() {
+ onChangeLoc(function() {
+ locIndex = (locIndex - 1 + locs.length) % locs.length;
+ });
+ });
+
+ example.querySelector('.next')
+ .addEventListener('click', function() {
+ onChangeLoc(function() {
+ locIndex = (locIndex + 1) % locs.length;
+ });
+ });
+ }
+
+ var expandButton = example.querySelector('.expand');
+ if (expandButton) {
+ expandButton.addEventListener('click', function () {
+ if (hasClass(example, "expanded")) {
+ removeClass(example, "expanded");
+ scrollToLoc(example, locs[0][0]);
+ } else {
+ addClass(example, "expanded");
+ }
+ });
+ }
+
+ // Start with the first example in view
+ scrollToLoc(example, locs[0][0]);
+ }
+
+ var firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example');
+ onEach(firstExamples, updateScrapedExample);
+ onEach(document.querySelectorAll('.more-examples-toggle'), function(toggle) {
+ // Allow users to click the left border of the <details> section to close it,
+ // since the section can be large and finding the [+] button is annoying.
+ toggle.querySelector('.toggle-line').addEventListener('click', function() {
+ toggle.open = false;
+ });
+
+ var moreExamples = toggle.querySelectorAll('.scraped-example');
+ toggle.querySelector('summary').addEventListener('click', function() {
+ // Wrapping in setTimeout ensures the update happens after the elements are actually
+ // visible. This is necessary since updateScrapedExample calls scrollToLoc which
+ // depends on offsetHeight, a property that requires an element to be visible to
+ // compute correctly.
+ setTimeout(function() { onEach(moreExamples, updateScrapedExample); });
+ }, {once: true});
+ });
+})();
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) {
/// Storage, used to store documentation settings.
crate static STORAGE_JS: &str = include_str!("static/js/storage.js");
+/// The file contents of `scraped-examples.js`, which contains functionality related to the
+/// --scrape-examples flag that inserts automatically-found examples of usages of items.
+crate static SCRAPE_EXAMPLES_JS: &str = include_str!("static/js/scrape-examples.js");
+
/// The file contents of `brush.svg`, the icon used for the theme-switch button.
crate static BRUSH_SVG: &[u8] = include_bytes!("static/images/brush.svg");
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.
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 %}
.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(),
}
TraitAlias => ItemKind::TraitAlias,
ProcAttribute => ItemKind::ProcAttribute,
ProcDerive => ItemKind::ProcDerive,
+ Generic => unreachable!(),
}
}
}
extern crate rustc_lexer;
extern crate rustc_lint;
extern crate rustc_lint_defs;
+extern crate rustc_macros;
extern crate rustc_metadata;
extern crate rustc_middle;
extern crate rustc_parse;
extern crate rustc_passes;
extern crate rustc_resolve;
+extern crate rustc_serialize;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
}}
}
-#[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
crate mod lint;
mod markdown;
mod passes;
+mod scrape_examples;
mod theme;
mod visit_ast;
mod visit_lib;
"Make the identifiers in the HTML source code pages navigable",
)
}),
+ unstable("scrape-examples-output-path", |o| {
+ o.optopt(
+ "",
+ "scrape-examples-output-path",
+ "",
+ "collect function call information and output at the given path",
+ )
+ }),
+ unstable("scrape-examples-target-crate", |o| {
+ o.optmulti(
+ "",
+ "scrape-examples-target-crate",
+ "",
+ "collect function call information for functions from the target crate",
+ )
+ }),
+ unstable("with-examples", |o| {
+ o.optmulti(
+ "",
+ "with-examples",
+ "",
+ "path to function call information (for displaying examples in the documentation)",
+ )
+ }),
]
}
// FIXME: fix this clone (especially render_options)
let manual_passes = options.manual_passes.clone();
let render_options = options.render_options.clone();
+ let scrape_examples_options = options.scrape_examples_options.clone();
let config = core::create_config(options);
interface::create_compiler_and_run(config, |compiler| {
// 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() {
sess.fatal("Compilation failed, aborting rustdoc");
});
info!("finished with rustc");
+ if let Some(options) = scrape_examples_options {
+ return scrape_examples::run(krate, render_opts, cache, tcx, options);
+ }
+
cache.crate_version = crate_version;
if show_coverage {
) {
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(
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();
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);
}
}
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(
) -> 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),
}
// 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);
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 crate::core::DocContext;
use crate::fold::DocFolder;
-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;
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()))
+ 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()))
|| blanket_impl.is_some()
} else {
true
}
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 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"
--- /dev/null
+//! This module analyzes crates to find call sites that can serve as examples in the documentation.
+
+use crate::clean;
+use crate::config;
+use crate::formats;
+use crate::formats::renderer::FormatRenderer;
+use crate::html::render::Context;
+
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::{
+ self as hir,
+ intravisit::{self, Visitor},
+ HirId,
+};
+use rustc_interface::interface;
+use rustc_macros::{Decodable, Encodable};
+use rustc_middle::hir::map::Map;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_serialize::{
+ opaque::{Decoder, FileEncoder},
+ Decodable, Encodable,
+};
+use rustc_session::getopts;
+use rustc_span::{
+ def_id::{CrateNum, DefPathHash, LOCAL_CRATE},
+ edition::Edition,
+ BytePos, FileName, SourceFile,
+};
+
+use std::fs;
+use std::path::PathBuf;
+
+#[derive(Debug, Clone)]
+crate struct ScrapeExamplesOptions {
+ output_path: PathBuf,
+ target_crates: Vec<String>,
+}
+
+impl ScrapeExamplesOptions {
+ crate fn new(
+ matches: &getopts::Matches,
+ diag: &rustc_errors::Handler,
+ ) -> Result<Option<Self>, i32> {
+ let output_path = matches.opt_str("scrape-examples-output-path");
+ let target_crates = matches.opt_strs("scrape-examples-target-crate");
+ match (output_path, !target_crates.is_empty()) {
+ (Some(output_path), true) => Ok(Some(ScrapeExamplesOptions {
+ output_path: PathBuf::from(output_path),
+ target_crates,
+ })),
+ (Some(_), false) | (None, true) => {
+ diag.err(&format!("must use --scrape-examples-output-path and --scrape-examples-target-crate together"));
+ Err(1)
+ }
+ (None, false) => Ok(None),
+ }
+ }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct SyntaxRange {
+ crate byte_span: (u32, u32),
+ crate line_span: (usize, usize),
+}
+
+impl SyntaxRange {
+ fn new(span: rustc_span::Span, file: &SourceFile) -> Self {
+ let get_pos = |bytepos: BytePos| file.original_relative_byte_pos(bytepos).0;
+ let get_line = |bytepos: BytePos| file.lookup_line(bytepos).unwrap();
+
+ SyntaxRange {
+ byte_span: (get_pos(span.lo()), get_pos(span.hi())),
+ line_span: (get_line(span.lo()), get_line(span.hi())),
+ }
+ }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct CallLocation {
+ crate call_expr: SyntaxRange,
+ crate enclosing_item: SyntaxRange,
+}
+
+impl CallLocation {
+ fn new(
+ tcx: TyCtxt<'_>,
+ expr_span: rustc_span::Span,
+ expr_id: HirId,
+ 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),
+ }
+ }
+}
+
+#[derive(Encodable, Decodable, Debug, Clone)]
+crate struct CallData {
+ crate locations: Vec<CallLocation>,
+ crate url: String,
+ crate display_name: String,
+ crate edition: Edition,
+}
+
+crate type FnCallLocations = FxHashMap<PathBuf, CallData>;
+crate type AllCallLocations = FxHashMap<DefPathHash, FnCallLocations>;
+
+/// Visitor for traversing a crate and finding instances of function calls.
+struct FindCalls<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ map: Map<'tcx>,
+ cx: Context<'tcx>,
+ target_crates: Vec<CrateNum>,
+ calls: &'a mut AllCallLocations,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for FindCalls<'a, 'tcx>
+where
+ 'tcx: 'a,
+{
+ type Map = Map<'tcx>;
+
+ fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
+ intravisit::NestedVisitorMap::OnlyBodies(self.map)
+ }
+
+ 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;
+ 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)
+ }
+ hir::ExprKind::MethodCall(_, _, _, span) => {
+ let types = tcx.typeck(ex.hir_id.owner);
+ let def_id = types.type_dependent_def_id(ex.hir_id).unwrap();
+ (tcx.type_of(def_id), span)
+ }
+ _ => {
+ return;
+ }
+ };
+
+ // 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() {
+ return;
+ }
+
+ // 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) {
+ return;
+ }
+
+ let file = tcx.sess.source_map().lookup_char_pos(span.lo()).file;
+ let file_path = match file.name.clone() {
+ FileName::Real(real_filename) => real_filename.into_local_path(),
+ _ => None,
+ };
+
+ if let Some(file_path) = file_path {
+ let abs_path = fs::canonicalize(file_path.clone()).unwrap();
+ let cx = &self.cx;
+ let mk_call_data = || {
+ let clean_span = crate::clean::types::Span::new(span);
+ let url = cx.href_from_span(clean_span, false).unwrap();
+ let display_name = file_path.display().to_string();
+ let edition = span.edition();
+ CallData { locations: Vec::new(), url, display_name, edition }
+ };
+
+ 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);
+ fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location);
+ }
+ }
+ }
+}
+
+crate fn run(
+ krate: clean::Crate,
+ renderopts: config::RenderOptions,
+ cache: formats::cache::Cache,
+ tcx: TyCtxt<'_>,
+ options: ScrapeExamplesOptions,
+) -> interface::Result<()> {
+ let inner = move || -> Result<(), String> {
+ // Generates source files for examples
+ let (cx, _) = Context::init(krate, renderopts, cache, tcx).map_err(|e| e.to_string())?;
+
+ // Collect CrateIds corresponding to provided target crates
+ // If two different versions of the crate in the dependency tree, then examples will be collcted from both.
+ let all_crates = tcx
+ .crates(())
+ .iter()
+ .chain([&LOCAL_CRATE])
+ .map(|crate_num| (crate_num, tcx.crate_name(*crate_num)))
+ .collect::<Vec<_>>();
+ let target_crates = options
+ .target_crates
+ .into_iter()
+ .map(|target| all_crates.iter().filter(move |(_, name)| name.as_str() == target))
+ .flatten()
+ .map(|(crate_num, _)| **crate_num)
+ .collect::<Vec<_>>();
+
+ debug!("All crates in TyCtxt: {:?}", all_crates);
+ debug!("Scrape examples target_crates: {:?}", target_crates);
+
+ // Run call-finder on all items
+ let mut calls = FxHashMap::default();
+ 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());
+
+ // 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())?;
+ encoder.flush().map_err(|e| e.to_string())?;
+
+ Ok(())
+ };
+
+ if let Err(e) = inner() {
+ tcx.sess.fatal(&e);
+ }
+
+ Ok(())
+}
+
+// Note: the Handler must be passed in explicitly because sess isn't available while parsing options
+crate fn load_call_locations(
+ with_examples: Vec<String>,
+ diag: &rustc_errors::Handler,
+) -> Result<AllCallLocations, i32> {
+ let inner = || {
+ let mut all_calls: AllCallLocations = FxHashMap::default();
+ for path in with_examples {
+ let bytes = fs::read(&path).map_err(|e| format!("{} (for path {})", e, path))?;
+ let mut decoder = Decoder::new(&bytes, 0);
+ let calls = AllCallLocations::decode(&mut decoder)?;
+
+ for (function, fn_calls) in calls.into_iter() {
+ all_calls.entry(function).or_default().extend(fn_calls.into_iter());
+ }
+ }
+
+ Ok(all_calls)
+ };
+
+ inner().map_err(|e: String| {
+ diag.err(&format!("failed to load examples: {}", e));
+ 1
+ })
+}
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"
}
}
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: -O
// compile-flags: --target aarch64-unknown-linux-gnu
-// min-llvm-version: 12.0
// assembly-output: emit-asm
// compile-flags: -O
// compile-flags: --target aarch64-unknown-linux-gnu
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: --target aarch64-unknown-linux-gnu
// needs-llvm-components: aarch64
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: -O
// compile-flags: --target armv7-unknown-linux-gnueabihf
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: --target armv7-unknown-linux-gnueabihf
// compile-flags: -C target-feature=+neon
-// min-llvm-version: 10.0.1
// only-x86_64
// assembly-output: emit-asm
// compile-flags: -C llvm-args=--x86-asm-syntax=intel
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: --target hexagon-unknown-linux-musl
// needs-llvm-components: hexagon
-// min-llvm-version: 10.0.1
// revisions: mips32 mips64
// assembly-output: emit-asm
//[mips32] compile-flags: --target mips-unknown-linux-gnu
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: --target nvptx64-nvidia-cuda
// compile-flags: --crate-type cdylib
-// min-llvm-version: 10.0.1
+// min-llvm-version: 12.0.1
// revisions: powerpc powerpc64
// assembly-output: emit-asm
//[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
-// min-llvm-version: 10.0.1
// revisions: riscv64 riscv32
// assembly-output: emit-asm
//[riscv64] compile-flags: --target riscv64imac-unknown-none-elf
//[riscv32] compile-flags: --target riscv32imac-unknown-none-elf
//[riscv32] needs-llvm-components: riscv
// compile-flags: -C target-feature=+d
-// min-system-llvm-version: 12.0
#![feature(no_core, lang_items, rustc_attrs)]
#![crate_type = "rlib"]
-// min-llvm-version: 10.0.1
// revisions: s390x
// assembly-output: emit-asm
//[s390x] compile-flags: --target s390x-unknown-linux-gnu
-// min-llvm-version: 10.0.1
// assembly-output: emit-asm
// compile-flags: --target wasm32-unknown-unknown
// compile-flags: --crate-type cdylib
-// min-llvm-version: 10.0.1
// revisions: x86_64 i686
// assembly-output: emit-asm
// compile-flags: -O
-// min-llvm-version: 10.0.1
// revisions: x86_64 i686
// assembly-output: emit-asm
//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
-// min-llvm-version: 12.0.0
// revisions: x64 A64 ppc64le
// assembly-output: emit-asm
// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static
//
// no-system-llvm
-// min-llvm-version: 10.0.1
// compile-flags: -O
#![crate_type="lib"]
-// min-llvm-version: 10.0.1
// revisions: powerpc powerpc64 powerpc64le
//[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
//[powerpc] needs-llvm-components: powerpc
-// min-llvm-version: 11.0.0
// compile-flags: -O
// ignore-debug: the debug assertions get in the way
#![crate_type = "lib"]
// This test checks an optimization that is not guaranteed to work. This test case should not block
// a future LLVM update.
// compile-flags: -O
-// min-llvm-version: 11.0
#![crate_type = "lib"]
// This test checks an optimization that is not guaranteed to work. This test case should not block
// a future LLVM update.
// compile-flags: -O
-// min-llvm-version: 11.0
#![crate_type = "lib"]
// compile-flags: -O
-// min-llvm-version: 11.0
#![crate_type = "lib"]
// compile-flags: -O -C no-prepopulate-passes
-//
-// min-system-llvm-version: 12.0
#![crate_type = "lib"]
#![feature(rustc_attrs)]
// compile-flags: -O
-// min-llvm-version: 11.0
#![crate_type = "lib"]
-// min-llvm-version: 12.0.0
// compile-flags: -O
#![crate_type = "lib"]
-// min-llvm-version: 11.0.0
// compile-flags: -O
// ignore-debug: the debug assertions get in the way
#![crate_type = "lib"]
// This test checks that bounds checks are elided when
// index is part of a (x | y) < C style condition
-// min-llvm-version: 11.0.0
// compile-flags: -O
#![crate_type = "lib"]
// Regression test for #75525, verifies that no bounds checks are generated.
-// min-llvm-version: 12.0.0
// compile-flags: -O
#![crate_type = "lib"]
-// min-llvm-version: 12.0.0
// compile-flags: -O
#![crate_type = "lib"]
-// min-llvm-version: 12.0.0
// compile-flags: -O
#![crate_type = "lib"]
-// min-llvm-version: 12.0
// compile-flags: -C opt-level=3
#![crate_type = "lib"]
-// min-llvm-version: 12.0
// compile-flags: -C opt-level=3
#![crate_type = "lib"]
-// min-llvm-version: 12.0
// compile-flags: -C opt-level=3
#![crate_type = "lib"]
-// min-llvm-version: 12.0
// compile-flags: -C opt-level=3
#![crate_type = "lib"]
// compile-flags: -C no-prepopulate-passes
//
-// min-system-llvm-version: 12.0
// ignore-arm
// ignore-aarch64
// ignore-mips
// compile-flags: -C no-prepopulate-passes
//
-// min-system-llvm-version: 12.0
// ignore-aarch64
// ignore-emscripten
// ignore-mips64
// compile-flags: -C no-prepopulate-passes
//
-// min-system-llvm-version: 12.0
// only-mips64
// See repr-transparent.rs
--- /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"}
// compile-flags: -g -Z src-hash-algorithm=sha256
-// min-llvm-version: 11.0
#![crate_type = "lib"]
// ignore-debug: the debug assertions get in the way
// compile-flags: -O
-// min-llvm-version: 11.0
#![crate_type = "lib"]
// Ensure that trivial casts of vec elements are O(1)
// only-wasm32
// compile-flags: -C target-feature=-nontrapping-fptoint
-// min-llvm-version: 12.0
#![crate_type = "lib"]
// CHECK-LABEL: @cast_f64_i64
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, optimized_mir, typeck")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck, promoted_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir, typeck")]
#[rustc_clean(cfg="cfail6")]
pub fn change_iteration_variable_pattern() {
let mut _x = 0;
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes, promoted_mir")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir, optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, promoted_mir")]
#[rustc_clean(cfg="cfail6")]
pub fn change_iterable() {
let mut _x = 0;
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
pub fn add_loop_label_to_break() {
let mut _x = 0;
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
+#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
#[rustc_clean(cfg="cfail6")]
pub fn add_loop_label_to_continue() {
let mut _x = 0;
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/inline-generator.rs:8:11: 8:11
- let _1: std::ops::GeneratorState<<impl std::ops::Generator<bool> as std::ops::Generator<bool>>::Yield, <impl std::ops::Generator<bool> as std::ops::Generator<bool>>::Return>; // in scope 0 at $DIR/inline-generator.rs:9:9: 9:11
- let mut _2: std::pin::Pin<&mut impl std::ops::Generator<bool>>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32
- let mut _3: &mut impl std::ops::Generator<bool>; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31
- let mut _4: impl std::ops::Generator<bool>; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31
+ let _1: std::ops::GeneratorState<i32, bool>; // in scope 0 at $DIR/inline-generator.rs:9:9: 9:11
+ let mut _2: std::pin::Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:41]>; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:32
+ let mut _3: &mut [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:23: 9:31
+ let mut _4: [generator@$DIR/inline-generator.rs:15:5: 15:41]; // in scope 0 at $DIR/inline-generator.rs:9:28: 9:31
+ let mut _7: bool; // in scope 0 at $DIR/inline-generator.rs:9:14: 9:46
scope 1 {
debug _r => _1; // in scope 1 at $DIR/inline-generator.rs:9:9: 9:11
--- /dev/null
+// compile-flags: -Z mir-opt-level=3 -Z inline-mir
+// ignore-wasm32-bare compiled with panic=abort by default
+#![crate_type = "lib"]
+
+// EMIT_MIR issue_78442.bar.RevealAll.diff
+// EMIT_MIR issue_78442.bar.Inline.diff
+pub fn bar<P>(
+ // Error won't happen if "bar" is not generic
+ _baz: P,
+) {
+ hide_foo()();
+}
+
+fn hide_foo() -> impl Fn() {
+ // Error won't happen if "iterate" hasn't impl Trait or has generics
+ foo
+}
+
+fn foo() { // Error won't happen if "foo" isn't used in "iterate" or has generics
+}
--- /dev/null
+- // MIR for `bar` before Inline
++ // MIR for `bar` after Inline
+
+ fn bar(_1: P) -> () {
+ debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9
+ let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3
+ let _2: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
++ scope 1 (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo})) { // at $DIR/issue-78442.rs:11:5: 11:17
++ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+- _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
++ _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ // mir::Constant
+ // + span: $DIR/issue-78442.rs:11:5: 11:13
+ // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+ _3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+- _2 = <impl Fn<()> as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+- // mir::Constant
+- // + span: $DIR/issue-78442.rs:11:5: 11:15
+- // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl std::ops::Fn<()>, ()) -> <impl std::ops::Fn<()> as std::ops::FnOnce<()>>::Output {<impl std::ops::Fn<()> as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
++ _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $DIR/issue-78442.rs:11:5: 11:17
+ }
+
+ bb2: {
+- StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+- StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+- StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+- StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+- _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2
+- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
++ return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2
+ }
+
+- bb3: {
+- return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2
++ bb3 (cleanup): {
++ drop(_1) -> bb4; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+ }
+
+ bb4 (cleanup): {
+- drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
++ resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2
+ }
+
+- bb5 (cleanup): {
+- resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2
++ bb5: {
++ StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
++ StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
++ StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
++ StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
++ _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2
++ drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+ }
+ }
+
--- /dev/null
+- // MIR for `bar` before RevealAll
++ // MIR for `bar` after RevealAll
+
+ fn bar(_1: P) -> () {
+ debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:9:5: 9:9
+ let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:10:3: 10:3
+ let _2: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+- let mut _3: &impl std::ops::Fn<()>; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+- let _4: impl std::ops::Fn<()>; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
++ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
++ let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ // mir::Constant
+ // + span: $DIR/issue-78442.rs:11:5: 11:13
+ // + literal: Const { ty: fn() -> impl std::ops::Fn<()> {hide_foo}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb1: {
+ _3 = &_4; // scope 0 at $DIR/issue-78442.rs:11:5: 11:15
+ StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ nop; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ _2 = <impl Fn<()> as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:11:5: 11:17
+ // mir::Constant
+ // + span: $DIR/issue-78442.rs:11:5: 11:15
+ // + literal: Const { ty: for<'r> extern "rust-call" fn(&'r impl std::ops::Fn<()>, ()) -> <impl std::ops::Fn<()> as std::ops::FnOnce<()>>::Output {<impl std::ops::Fn<()> as std::ops::Fn<()>>::call}, val: Value(Scalar(<ZST>)) }
+ }
+
+ bb2: {
+ StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+ StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:11:16: 11:17
+ StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+ StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:11:17: 11:18
+ _0 = const (); // scope 0 at $DIR/issue-78442.rs:10:3: 12:2
+ drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+ }
+
+ bb3: {
+ return; // scope 0 at $DIR/issue-78442.rs:12:2: 12:2
+ }
+
+ bb4 (cleanup): {
+ drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:12:1: 12:2
+ }
+
+ bb5 (cleanup): {
+ resume; // scope 0 at $DIR/issue-78442.rs:7:1: 12:2
+ }
+ }
+
# needs-profiler-support
-# min-llvm-version: 11.0
-include ../coverage/coverage_tools.mk
# needs-profiler-support
# ignore-windows-gnu
-# min-llvm-version: 11.0
# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
# properly. Since we only have GCC on the CI ignore the test for now.
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
-include ../tools.mk
-# min-llvm-version: 11.0
-
all: off packed unpacked
ifeq ($(UNAME),Darwin)
-include ../tools.mk
# only-linux
-# min-llvm-version: 11.0
all:
$(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 foo.rs -g
--- /dev/null
+deps := ex ex2
+
+-include ./scrape.mk
+
+all: scrape
--- /dev/null
+fn main() {
+ foobar::ok();
+ foobar::ok();
+}
--- /dev/null
+fn main() {
+ foobar::ok();
+}
--- /dev/null
+-include ../../run-make-fulldeps/tools.mk
+
+OUTPUT_DIR := "$(TMPDIR)/rustdoc"
+
+$(TMPDIR)/%.calls: $(TMPDIR)/libfoobar.rmeta
+ $(RUSTDOC) examples/$*.rs --crate-name $* --crate-type bin --output $(OUTPUT_DIR) \
+ --extern foobar=$(TMPDIR)/libfoobar.rmeta \
+ -Z unstable-options \
+ --scrape-examples-output-path $@ \
+ --scrape-examples-target-crate foobar
+
+$(TMPDIR)/lib%.rmeta: src/lib.rs
+ $(RUSTC) src/lib.rs --crate-name $* --crate-type lib --emit=metadata
+
+scrape: $(foreach d,$(deps),$(TMPDIR)/$(d).calls)
+ $(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \
+ -Z unstable-options \
+ $(foreach d,$(deps),--with-examples $(TMPDIR)/$(d).calls)
+
+ $(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
--- /dev/null
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]//*[@class="prev"]' ''
+// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' ''
+
+pub fn ok() {}
--- /dev/null
+deps := ex1 ex2
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
--- /dev/null
+fn main() {
+ foobar::ok();
+
+ // this is a
+
+ // BIG
+
+ // item
+}
--- /dev/null
+fn main() {
+ foobar::ok();
+ // small item
+}
--- /dev/null
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]' 'ex2'
+// @has foobar/fn.ok.html '//*[@class="more-scraped-examples"]' 'ex1'
+
+pub fn ok() {}
--- /dev/null
+deps := ex
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
--- /dev/null
+fn main() {
+ foobar::b::foo();
+ foobar::c::foo();
+}
--- /dev/null
+pub fn foo() {}
--- /dev/null
+// @has foobar/b/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs'
+// @has foobar/c/fn.foo.html '//*[@class="scraped-example expanded"]' 'ex.rs'
+
+#[path = "a.rs"]
+pub mod b;
+
+#[path = "a.rs"]
+pub mod c;
--- /dev/null
+// The `impl Foo` heading underneath `Implementations` has a §
+// anchor to its left (used for linking to that heading). The anchor only shows
+// up when hovering the `impl Foo`. This test ensures there's no gap between the
+// anchor and the `impl Foo`. If there were a gap, this would cause an annoying
+// problem: you hover `impl Foo` to see the anchor, then when you move your
+// mouse to the left, the anchor disappears before you reach it.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+// We check that ".item-info" is bigger than its content.
+move-cursor-to: ".impl"
+assert-property: (".impl > a.anchor", {"offsetWidth": "9"})
+assert-css: (".impl > a.anchor", {"left": "-8px"})
--- /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"})
+
+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"})
// 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-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(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"
}
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
+// compile-flags: -Z unstable-options --scrape-examples-target-crate foobar
--- /dev/null
+error: must use --scrape-examples-output-path and --scrape-examples-target-crate together
+
--- /dev/null
+// compile-flags: -Z unstable-options --scrape-examples-output-path ex.calls
--- /dev/null
+error: must use --scrape-examples-output-path and --scrape-examples-target-crate together
+
--- /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'
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!()
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`.
-// min-llvm-version: 10.0.1
// only-aarch64
// run-pass
// revisions: mirunsafeck thirunsafeck
-// min-llvm-version: 10.0.1
// only-aarch64
// build-fail
// compile-flags: -Ccodegen-units=1
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:11:15
+ --> $DIR/srcloc.rs:10:15
|
LL | asm!("invalid_instruction");
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:15:13
+ --> $DIR/srcloc.rs:14:13
|
LL | invalid_instruction
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:20:13
+ --> $DIR/srcloc.rs:19:13
|
LL | invalid_instruction
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:26:13
+ --> $DIR/srcloc.rs:25:13
|
LL | invalid_instruction
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:33:13
+ --> $DIR/srcloc.rs:32:13
|
LL | invalid_instruction
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:38:14
+ --> $DIR/srcloc.rs:37:14
|
LL | asm!(concat!("invalid", "_", "instruction"));
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:42:14
+ --> $DIR/srcloc.rs:41:14
|
LL | "invalid_instruction",
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:48:14
+ --> $DIR/srcloc.rs:47:14
|
LL | "invalid_instruction",
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:55:14
+ --> $DIR/srcloc.rs:54:14
|
LL | "invalid_instruction",
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:62:13
+ --> $DIR/srcloc.rs:61:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:69:13
+ --> $DIR/srcloc.rs:68:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:76:14
+ --> $DIR/srcloc.rs:75:14
|
LL | "invalid_instruction1",
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:77:14
+ --> $DIR/srcloc.rs:76:14
|
LL | "invalid_instruction2",
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:83:13
+ --> $DIR/srcloc.rs:82:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:83:13
+ --> $DIR/srcloc.rs:82:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:92:13
+ --> $DIR/srcloc.rs:91:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:92:13
+ --> $DIR/srcloc.rs:91:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:96:13
+ --> $DIR/srcloc.rs:95:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:96:13
+ --> $DIR/srcloc.rs:95:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:107:13
+ --> $DIR/srcloc.rs:106:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:107:13
+ --> $DIR/srcloc.rs:106:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:111:13
+ --> $DIR/srcloc.rs:110:13
|
LL | concat!(
| ^
| ^
error: unrecognized instruction mnemonic
- --> $DIR/srcloc.rs:111:13
+ --> $DIR/srcloc.rs:110:13
|
LL | concat!(
| ^
-// min-llvm-version: 10.0.1
// only-aarch64
// only-linux
// run-pass
-// min-llvm-version: 10.0.1
// only-x86_64
// run-pass
// revisions: mirunsafeck thirunsafeck
--- /dev/null
+// build-pass
+// only-x86_64
+
+#![feature(asm, target_feature_11)]
+
+#[target_feature(enable = "avx")]
+fn main() {
+ unsafe {
+ asm!(
+ "/* {} */",
+ out(ymm_reg) _,
+ );
+ }
+}
-// min-llvm-version: 10.0.1
// only-x86_64
// build-fail
// compile-flags: -Ccodegen-units=1
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:11:15
+ --> $DIR/srcloc.rs:10:15
|
LL | asm!("invalid_instruction");
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:15:13
+ --> $DIR/srcloc.rs:14:13
|
LL | invalid_instruction
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:20:13
+ --> $DIR/srcloc.rs:19:13
|
LL | invalid_instruction
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:26:13
+ --> $DIR/srcloc.rs:25:13
|
LL | invalid_instruction
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:33:13
+ --> $DIR/srcloc.rs:32:13
|
LL | invalid_instruction
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:38:14
+ --> $DIR/srcloc.rs:37:14
|
LL | asm!(concat!("invalid", "_", "instruction"));
| ^
| ^^^^^^^^^^^^^^^^^^^
warning: scale factor without index register is ignored
- --> $DIR/srcloc.rs:41:15
+ --> $DIR/srcloc.rs:40:15
|
LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
| ^
| ^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:45:14
+ --> $DIR/srcloc.rs:44:14
|
LL | "invalid_instruction",
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:51:14
+ --> $DIR/srcloc.rs:50:14
|
LL | "invalid_instruction",
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:58:14
+ --> $DIR/srcloc.rs:57:14
|
LL | "invalid_instruction",
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:65:13
+ --> $DIR/srcloc.rs:64:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction'
- --> $DIR/srcloc.rs:72:13
+ --> $DIR/srcloc.rs:71:13
|
LL | concat!("invalid", "_", "instruction"),
| ^
| ^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:79:14
+ --> $DIR/srcloc.rs:78:14
|
LL | "invalid_instruction1",
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:80:14
+ --> $DIR/srcloc.rs:79:14
|
LL | "invalid_instruction2",
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:86:13
+ --> $DIR/srcloc.rs:85:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:86:13
+ --> $DIR/srcloc.rs:85:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:95:13
+ --> $DIR/srcloc.rs:94:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:95:13
+ --> $DIR/srcloc.rs:94:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction3'
- --> $DIR/srcloc.rs:99:13
+ --> $DIR/srcloc.rs:98:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction4'
- --> $DIR/srcloc.rs:99:13
+ --> $DIR/srcloc.rs:98:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction1'
- --> $DIR/srcloc.rs:110:13
+ --> $DIR/srcloc.rs:109:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction2'
- --> $DIR/srcloc.rs:110:13
+ --> $DIR/srcloc.rs:109:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction3'
- --> $DIR/srcloc.rs:114:13
+ --> $DIR/srcloc.rs:113:13
|
LL | concat!(
| ^
| ^^^^^^^^^^^^^^^^^^^^
error: invalid instruction mnemonic 'invalid_instruction4'
- --> $DIR/srcloc.rs:114:13
+ --> $DIR/srcloc.rs:113:13
|
LL | concat!(
| ^
-// min-llvm-version: 10.0.1
+// min-llvm-version: 12.0.1
// only-x86_64
// only-linux
// run-pass
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`.
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
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:21: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
error: future cannot be sent between threads safely
- --> $DIR/issue-71137.rs:20:3
+ --> $DIR/issue-71137.rs:20: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
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
-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
+// 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();
+}
// build-fail
// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
// needs-llvm-components: arm
-// min-llvm-version: 11.0
#![feature(abi_c_cmse_nonsecure_call, no_core, lang_items, intrinsics)]
#![no_core]
#[lang="sized"]
// build-fail
// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
// needs-llvm-components: arm
-// min-llvm-version: 11.0
#![feature(cmse_nonsecure_entry, no_core, lang_items)]
#![no_core]
#[lang="sized"]
--- /dev/null
+#![crate_type = "lib"]
+#![feature(negative_impls)]
+
+pub trait Error {}
+impl !Error for &str {}
--- /dev/null
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+#![feature(trait_alias)]
+
+trait A {}
+trait B {}
+trait AB = A + B;
+
+impl !A for u32 {}
+
+trait C {}
+#[rustc_strict_coherence]
+impl<T: AB> C for T {}
+#[rustc_strict_coherence]
+impl C for u32 {}
+//~^ ERROR: conflicting implementations of trait `C` for type `u32` [E0119]
+// FIXME this should work, we should implement an `assemble_neg_candidates` fn
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `C` for type `u32`
+ --> $DIR/coherence-overlap-negate-alias-strict.rs:15:1
+ |
+LL | impl<T: AB> C for T {}
+ | ------------------- first implementation here
+LL | #[rustc_strict_coherence]
+LL | impl C for u32 {}
+ | ^^^^^^^^^^^^^^ conflicting implementation for `u32`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
--- /dev/null
+use std::ops::DerefMut;
+
+trait Foo {}
+impl<T: DerefMut> Foo for T {}
+impl<U> Foo for &U {}
+//~^ ERROR: conflicting implementations of trait `Foo` for type `&_` [E0119]
+
+fn main() {}
--- /dev/null
+error[E0119]: conflicting implementations of trait `Foo` for type `&_`
+ --> $DIR/coherence-overlap-negate-not-use-feature-gate.rs:5:1
+ |
+LL | impl<T: DerefMut> Foo for T {}
+ | --------------------------- first implementation here
+LL | impl<U> Foo for &U {}
+ | ^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
--- /dev/null
+// check-pass
+
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+#![feature(trait_alias)]
+
+trait A {}
+trait B {}
+
+impl !A for u32 {}
+
+trait C {}
+#[rustc_strict_coherence]
+impl<T: A + B> C for T {}
+#[rustc_strict_coherence]
+impl C for u32 {}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+#![feature(negative_impls)]
+
+use std::ops::DerefMut;
+
+trait Foo {}
+impl<T: DerefMut> Foo for T {}
+impl<U> Foo for &U {}
+
+fn main() {}
--- /dev/null
+// check-pass
+// aux-build:error_lib.rs
+//
+// Check that if we promise to not impl what would overlap it doesn't actually overlap
+
+#![feature(negative_impls)]
+
+extern crate error_lib as lib;
+use lib::Error;
+
+trait From<T> {}
+
+impl From<&str> for Box<dyn Error> {}
+impl<E> From<E> for Box<dyn Error> where E: Error {}
+
+fn main() {}
--- /dev/null
+#![feature(rustc_attrs)]
+#![feature(trait_alias)]
+
+trait A {}
+trait B {}
+trait AB = A + B;
+
+impl A for u32 {}
+impl B for u32 {}
+
+trait C {}
+#[rustc_strict_coherence]
+impl<T: AB> C for T {}
+#[rustc_strict_coherence]
+impl C for u32 {}
+//~^ ERROR
+// FIXME it's giving an ungreat error but unsure if we care given that it's using an internal rustc
+// attribute and an artificial code path for testing purposes
+
+fn main() {}
--- /dev/null
+error[E0283]: type annotations needed
+ --> $DIR/coherence-overlap-trait-alias.rs:15:6
+ |
+LL | impl C for u32 {}
+ | ^ cannot infer type for type `u32`
+ |
+note: multiple `impl`s satisfying `u32: C` found
+ --> $DIR/coherence-overlap-trait-alias.rs:13:1
+ |
+LL | impl<T: AB> C for T {}
+ | ^^^^^^^^^^^^^^^^^^^
+LL | #[rustc_strict_coherence]
+LL | impl C for u32 {}
+ | ^^^^^^^^^^^^^^
+note: required by a bound in `C`
+ --> $DIR/coherence-overlap-trait-alias.rs:11:1
+ |
+LL | trait C {}
+ | ^^^^^^^ required by this bound in `C`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
--- /dev/null
+// Regression test for issue #89358.
+
+// compile-flags: --cfg a"
+// error-pattern: unterminated double quote string
+// error-pattern: this error occurred on the command line
--- /dev/null
+error[E0765]: unterminated double quote string
+ |
+ = note: this error occurred on the command line: `--cfg=a"`
+
#![feature(staged_api)]
#![feature(const_generics_defaults)]
#![allow(incomplete_features)]
-// FIXME(const_generics): It seems like we aren't testing the right thing here,
+// FIXME(const_generics_defaults): It seems like we aren't testing the right thing here,
// I would assume that we want the attributes to apply to the const parameter defaults
// themselves.
#![stable(feature = "const_default_test", since="none")]
--- /dev/null
+#![feature(const_generics_defaults)]
+
+// test that defaulted const params are not used to help type inference
+
+struct Foo<const N: u32 = 2>;
+
+impl<const N: u32> Foo<N> {
+ fn foo() -> Self { loop {} }
+}
+
+fn main() {
+ let foo = Foo::<1>::foo();
+ let foo = Foo::foo();
+ //~^ error: type annotations needed for `Foo<{_: u32}>`
+}
--- /dev/null
+error[E0282]: type annotations needed for `Foo<{_: u32}>`
+ --> $DIR/doesnt_infer.rs:13:15
+ |
+LL | let foo = Foo::foo();
+ | --- ^^^^^^^^ cannot infer the value of const parameter `N`
+ | |
+ | consider giving `foo` the explicit type `Foo<{_: u32}>`, where the type parameter `N` is specified
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
--- /dev/null
+// run-pass
+#![feature(const_generics_defaults)]
+
+struct Uwu<const N: u32 = 1, const M: u32 = N>;
+
+trait Trait {}
+impl<const N: u32> Trait for Uwu<N> {}
+
+fn rawr<const N: u32>() -> impl Trait {
+ Uwu::<N>
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> { }
+
+impl<const N: u8> Traitor<N> for u32 {}
+impl Traitor<1, 1> for u64 {}
+
+fn uwu<const N: u8>() -> impl Traitor<N> {
+ 1_u32
+}
+
+fn owo() -> impl Traitor {
+ 1_u64
+}
+
+fn main() {
+ rawr::<3>();
+ rawr::<7>();
+ uwu::<{ u8::MAX }>();
+ owo();
+}
--- /dev/null
+#![feature(const_generics_defaults)]
+
+struct Uwu<const N: u32 = 1, const M: u32 = N>;
+
+trait Trait {}
+impl<const N: u32> Trait for Uwu<N> {}
+
+fn rawr() -> impl Trait {
+ //~^ error: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
+ Uwu::<10, 12>
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> { }
+
+impl<const N: u8> Traitor<N, 2> for u32 {}
+impl Traitor<1, 2> for u64 {}
+
+
+fn uwu<const N: u8>() -> impl Traitor<N> {
+ //~^ error: the trait bound `u32: Traitor<N, N>` is not satisfied
+ 1_u32
+}
+
+fn owo() -> impl Traitor {
+ //~^ error: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
+ 1_u64
+}
+
+fn main() {
+ rawr();
+ uwu();
+ owo();
+}
--- /dev/null
+error[E0277]: the trait bound `Uwu<10_u32, 12_u32>: Trait` is not satisfied
+ --> $DIR/rp_impl_trait_fail.rs:8:14
+ |
+LL | fn rawr() -> impl Trait {
+ | ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10_u32, 12_u32>`
+ |
+ = help: the following implementations were found:
+ <Uwu<N> as Trait>
+
+error[E0277]: the trait bound `u32: Traitor<N, N>` is not satisfied
+ --> $DIR/rp_impl_trait_fail.rs:19:26
+ |
+LL | fn uwu<const N: u8>() -> impl Traitor<N> {
+ | ^^^^^^^^^^^^^^^ the trait `Traitor<N, N>` is not implemented for `u32`
+ |
+ = help: the following implementations were found:
+ <u32 as Traitor<N, 2_u8>>
+
+error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
+ --> $DIR/rp_impl_trait_fail.rs:24:13
+ |
+LL | fn owo() -> impl Traitor {
+ | ^^^^^^^^^^^^ the trait `Traitor<1_u8, 1_u8>` is not implemented for `u64`
+ |
+ = help: the following implementations were found:
+ <u64 as Traitor<1_u8, 2_u8>>
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// run-pass
+#![feature(const_generics_defaults)]
+
+trait Trait<const N: u8 = 12> {
+ fn uwu(&self) -> u8 {
+ N
+ }
+}
+
+impl Trait for u32 {}
+
+impl Trait<12> for u64 {
+ fn uwu(&self) -> u8 {
+ *self as u8
+ }
+}
+
+fn foo(arg: &dyn Trait) -> u8 {
+ arg.uwu()
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> {
+ fn owo(&self) -> u8 {
+ M
+ }
+}
+
+impl Traitor<2> for bool { }
+impl Traitor for u8 {
+ fn owo(&self) -> u8 {
+ *self
+ }
+}
+
+fn bar<const N: u8>(arg: &dyn Traitor<N>) -> u8 {
+ arg.owo()
+}
+
+fn main() {
+ assert_eq!(foo(&10_u32), 12);
+ assert_eq!(foo(&3_u64), 3);
+
+ assert_eq!(bar(&true), 2);
+ assert_eq!(bar(&1_u8), 1);
+}
--- /dev/null
+#![feature(const_generics_defaults)]
+
+trait Trait<const N: u8 = 12> {
+ fn uwu(&self) -> u8 {
+ N
+ }
+}
+
+impl Trait<2> for u32 {}
+
+fn foo(arg: &dyn Trait) -> u8 {
+ arg.uwu()
+}
+
+trait Traitor<const N: u8 = 1, const M: u8 = N> {
+ fn owo(&self) -> u8 {
+ M
+ }
+}
+
+impl Traitor<2, 3> for bool { }
+
+fn bar<const N: u8>(arg: &dyn Traitor<N>) -> u8 {
+ arg.owo()
+}
+
+fn main() {
+ foo(&10_u32);
+ //~^ error: the trait bound `u32: Trait` is not satisfied
+ bar(&true);
+ //~^ error: the trait bound `bool: Traitor<{_: u8}, {_: u8}>` is not satisfied
+}
--- /dev/null
+error[E0277]: the trait bound `u32: Trait` is not satisfied
+ --> $DIR/trait_objects_fail.rs:28:9
+ |
+LL | foo(&10_u32);
+ | --- ^^^^^^^ the trait `Trait` is not implemented for `u32`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the following implementations were found:
+ <u32 as Trait<2_u8>>
+ = note: required for the cast to the object type `dyn Trait`
+
+error[E0277]: the trait bound `bool: Traitor<{_: u8}, {_: u8}>` is not satisfied
+ --> $DIR/trait_objects_fail.rs:30:9
+ |
+LL | bar(&true);
+ | --- ^^^^^ the trait `Traitor<{_: u8}, {_: u8}>` is not implemented for `bool`
+ | |
+ | required by a bound introduced by this call
+ |
+ = help: the following implementations were found:
+ <bool as Traitor<2_u8, 3_u8>>
+ = note: required for the cast to the object type `dyn Traitor<{_: u8}, {_: u8}>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+#![feature(const_generics_defaults)]
+
+struct Ooopsies<const N: u8 = { u8::MAX + 1 }>;
+//~^ error: evaluation of constant value failed
+
+trait Trait<const N: u8> {}
+impl Trait<3> for () {}
+struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+//~^ error: the trait bound `(): Trait<2_u8>` is not satisfied
+
+trait Traitor<T, const N: u8> {}
+struct WhereClauseTooGeneric<T = u32, const N: u8 = 2>(T) where (): Traitor<T, N>;
+
+// no error on struct def
+struct DependentDefaultWfness<const N: u8 = 1, T = WhereClause<N>>(T);
+fn foo() -> DependentDefaultWfness {
+ //~^ error: the trait bound `(): Trait<1_u8>` is not satisfied
+ loop {}
+}
+
+fn main() {}
--- /dev/null
+error[E0080]: evaluation of constant value failed
+ --> $DIR/wfness.rs:3:33
+ |
+LL | struct Ooopsies<const N: u8 = { u8::MAX + 1 }>;
+ | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow
+
+error[E0277]: the trait bound `(): Trait<2_u8>` is not satisfied
+ --> $DIR/wfness.rs:8:47
+ |
+LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+ | ^^^^^^^^ the trait `Trait<2_u8>` is not implemented for `()`
+ |
+ = help: the following implementations were found:
+ <() as Trait<3_u8>>
+note: required by `WhereClause`
+ --> $DIR/wfness.rs:8:1
+ |
+LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `(): Trait<1_u8>` is not satisfied
+ --> $DIR/wfness.rs:16:13
+ |
+LL | fn foo() -> DependentDefaultWfness {
+ | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<1_u8>` is not implemented for `()`
+ |
+ = help: the following implementations were found:
+ <() as Trait<3_u8>>
+note: required by a bound in `WhereClause`
+ --> $DIR/wfness.rs:8:47
+ |
+LL | struct WhereClause<const N: u8 = 2> where (): Trait<N>;
+ | ^^^^^^^^ required by this bound in `WhereClause`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0080, E0277.
+For more information about an error, try `rustc --explain E0080`.
arg: T,
}
+struct Foo<const N: u8 = 3, T>(T);
+//~^ error: generic parameters with a default must be trailing
+
fn main() {}
LL | struct A<T = u32, const N: usize> {
| ^
-error: aborting due to previous error
+error: generic parameters with a default must be trailing
+ --> $DIR/wrong-order.rs:8:18
+ |
+LL | struct Foo<const N: u8 = 3, T>(T);
+ | ^
+
+error: aborting due to 2 previous errors
--- /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`
|
= help: consider moving this anonymous constant into a `const` function
-error[E0392]: parameter `T` is never used
- --> $DIR/issue-67375.rs:5:12
- |
-LL | struct Bug<T> {
- | ^ unused parameter
- |
- = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `T` to be a const parameter, use `const T: usize` instead
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-For more information about this error, try `rustc --explain E0392`.
#![cfg_attr(full, feature(generic_const_exprs))]
struct Bug<T> {
- //~^ ERROR parameter `T` is never used
+ //[min]~^ ERROR parameter `T` is never used
inner: [(); { [|_: &T| {}; 0].len() }],
//[min]~^ ERROR generic parameters may not be used in const operations
//[full]~^^ ERROR overly complex generic constant
= note: expected type parameter `S`
found union `MaybeUninit<_>`
-error[E0392]: parameter `S` is never used
- --> $DIR/issue-67945-1.rs:7:12
- |
-LL | struct Bug<S> {
- | ^ unused parameter
- |
- = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
- = help: if you intended `S` to be a const parameter, use `const S: usize` instead
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
-Some errors have detailed explanations: E0308, E0392.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0308`.
use std::mem::MaybeUninit;
struct Bug<S> {
- //~^ ERROR parameter `S` is never used
+ //[min]~^ ERROR parameter `S` is never used
A: [(); {
let x: S = MaybeUninit::uninit();
//[min]~^ ERROR generic parameters may not be used in const operations
--- /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
+// Regression test for issue 90013.
+// check-pass
+#![allow(incomplete_features)]
+#![feature(inline_const)]
+
+fn main() {
+ const { || {} };
+}
--- /dev/null
+// Regression test for issue #89938.
+// check-pass
+// compile-flags: --crate-type=lib
+#![feature(const_precise_live_drops)]
+
+pub const fn f() {
+ let _: Option<String> = None;
+ let _: &'static Option<String> = &None;
+}
--- /dev/null
+// Check that storage statements reset local qualification.
+// check-pass
+use std::cell::Cell;
+
+const C: Option<Cell<u32>> = {
+ let mut c = None;
+ let mut i = 0;
+ while i == 0 {
+ let mut x = None;
+ c = x;
+ x = Some(Cell::new(0));
+ let _ = x;
+ i += 1;
+ }
+ c
+};
+
+fn main() {
+ let _: &'static _ = &C;
+}
--- /dev/null
+// compile-flags: --crate-type=lib
+#![feature(const_mut_refs)]
+#![feature(const_precise_live_drops)]
+#![feature(const_swap)]
+
+// 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
+}
--- /dev/null
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:8: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:14: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:30:9
+ |
+LL | let _z = x;
+ | ^^ constants cannot evaluate destructors
+
+error[E0493]: destructors cannot be evaluated at compile-time
+ --> $DIR/qualif-indirect-mutation-fail.rs:35: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:43:9
+ |
+LL | let _y = x;
+ | ^^ constant functions cannot evaluate destructors
+
+error: aborting due to 5 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)]
+
+pub const fn f() {
+ let mut x: (Option<String>, u32) = (None, 0);
+ let mut a = 10;
+ *(&mut a) = 11;
+ x.1 = a;
+}
+
+pub const fn g() {
+ let mut a: (u32, Option<String>) = (0, None);
+ let _ = &mut a.0;
+}
--- /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`.
|
help: the following are the possible correct uses
|
-LL | #[deprecated]
- | ~~~~~~~~~~~~~
-LL | #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LL | #[deprecated = "reason"]
| ~~~~~~~~~~~~~~~~~~~~~~~~
+LL | #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | #[deprecated]
+ | ~~~~~~~~~~~~~
error: aborting due to previous error
found type `usize`
help: try using a variant of the expected enum
|
-LL | this_function_expects_a_double_option(DoubleOption::FirstSome(n));
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~
LL | this_function_expects_a_double_option(DoubleOption::AlternativeSome(n));
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | this_function_expects_a_double_option(DoubleOption::FirstSome(n));
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0308]: mismatched types
--> $DIR/issue-42764.rs:27:33
#![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
|
| this method call resolves to `T`
| help: use the fully qualified path for the potential candidate: `<Impl as Into<u32>>::into(foo_impl)`
|
- = note: cannot satisfy `Impl: Into<_>`
+note: multiple `impl`s satisfying `Impl: Into<_>` found
+ --> $DIR/E0283.rs:17:1
+ |
+LL | impl Into<u32> for Impl {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ = note: and another `impl` found in the `core` crate:
+ - impl<T, U> Into<U> for T
+ where U: From<T>;
error: aborting due to 2 previous errors
-struct Foo<'a: '_>(&'a u8); //~ ERROR cannot be used here
-fn foo<'a: '_>(_: &'a u8) {} //~ ERROR cannot be used here
+fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+ //~^ ERROR: `'_` cannot be used here [E0637]
+ //~| ERROR: missing lifetime specifier
+ if str1.len() > str2.len() {
+ str1
+ } else {
+ str2
+ }
+}
-struct Bar<'a>(&'a u8);
-impl<'a: '_> Bar<'a> { //~ ERROR cannot be used here
- fn bar() {}
+fn and_without_explicit_lifetime<T>()
+where
+ T: Into<&u32>, //~ ERROR: `&` without an explicit lifetime name cannot be used here [E0637]
+{
}
fn main() {}
error[E0637]: `'_` cannot be used here
- --> $DIR/E0637.rs:1:16
+ --> $DIR/E0637.rs:1:24
|
-LL | struct Foo<'a: '_>(&'a u8);
- | ^^ `'_` is a reserved lifetime name
+LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+ | ^^ `'_` is a reserved lifetime name
-error[E0637]: `'_` cannot be used here
- --> $DIR/E0637.rs:2:12
+error[E0637]: `&` without an explicit lifetime name cannot be used here
+ --> $DIR/E0637.rs:13:13
|
-LL | fn foo<'a: '_>(_: &'a u8) {}
- | ^^ `'_` is a reserved lifetime name
+LL | T: Into<&u32>,
+ | ^ explicit lifetime name needed here
-error[E0637]: `'_` cannot be used here
- --> $DIR/E0637.rs:5:10
+error[E0106]: missing lifetime specifier
+ --> $DIR/E0637.rs:1:62
+ |
+LL | fn underscore_lifetime<'_>(str1: &'_ str, str2: &'_ str) -> &'_ str {
+ | ------- ------- ^^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `str1` or `str2`
+help: consider introducing a named lifetime parameter
|
-LL | impl<'a: '_> Bar<'a> {
- | ^^ `'_` is a reserved lifetime name
+LL | fn underscore_lifetime<'a, '_>(str1: &'a str, str2: &'a str) -> &'a str {
+ | +++ ~~ ~~ ~~
error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0637`.
+Some errors have detailed explanations: E0106, E0637.
+For more information about an error, try `rustc --explain E0106`.
-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
|
--- /dev/null
+#[derive(Debug)]
+struct Machine<S> {
+ state: S,
+ common_field1: &'static str,
+ common_field2: i32,
+}
+#[derive(Debug)]
+struct State1;
+#[derive(Debug, PartialEq)]
+struct State2;
+
+fn update_to_state2() {
+ let m1: Machine<State1> = Machine {
+ state: State1,
+ common_field1: "hello",
+ common_field2: 2,
+ };
+ let m2: Machine<State2> = Machine {
+ state: State2,
+ ..m1 //~ ERROR mismatched types
+ };
+ // FIXME: this should trigger feature gate
+ assert_eq!(State2, m2.state);
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/feature-gate-type_changing_struct_update.rs:20:11
+ |
+LL | ..m1
+ | ^^ expected struct `State2`, found struct `State1`
+ |
+ = note: expected struct `Machine<State2>`
+ found struct `Machine<State1>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
|
help: the following are the possible correct uses
|
-LL | #[macro_use] struct S;
- | ~~~~~~~~~~~~
LL | #[macro_use(name1, name2, ...)] struct S;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | #[macro_use] struct S;
+ | ~~~~~~~~~~~~
error: aborting due to 4 previous errors
-// min-llvm-version: 12.0
// compile-flags: -C opt-level=3
// run-pass
--- /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`.
--- /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![]);
+}
--- /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
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,)>`
//~| expected `i32`, found `u32`
}
-fn sum_to(n: u32) -> impl Foo {
+fn sum_to(n: u32) -> impl Foo { //~ ERROR type annotations needed
if n == 0 {
0
} else {
|
= help: the trait `Add<impl Foo>` is not implemented for `u32`
-error: aborting due to 2 previous errors; 1 warning emitted
+error[E0283]: type annotations needed
+ --> $DIR/equality.rs:20:22
+ |
+LL | fn sum_to(n: u32) -> impl Foo {
+ | ^^^^^^^^ cannot infer type for type `{integer}`
+ |
+ = note: multiple `impl`s satisfying `{integer}: ToString` found in the `alloc` crate:
+ - impl ToString for i8;
+ - impl ToString for u8;
+note: required because of the requirements on the impl of `Foo` for `{integer}`
+ --> $DIR/equality.rs:5:26
+ |
+LL | impl<T: Copy + ToString> Foo for T {}
+ | ^^^ ^
+
+error: aborting due to 3 previous errors; 1 warning emitted
-Some errors have detailed explanations: E0277, E0308.
+Some errors have detailed explanations: E0277, E0283, E0308.
For more information about an error, try `rustc --explain E0277`.
|
LL | use foo::Bar;
|
+LL | use no_method_suggested_traits::Reexported;
+ |
LL | use no_method_suggested_traits::foo::PubPub;
|
LL | use no_method_suggested_traits::qux::PrivPub;
|
-LL | use no_method_suggested_traits::Reexported;
- |
error[E0599]: no method named `method` found for struct `Rc<&mut Box<&u32>>` in the current scope
--> $DIR/no-method-suggested-traits.rs:26:44
|
LL | use foo::Bar;
|
+LL | use no_method_suggested_traits::Reexported;
+ |
LL | use no_method_suggested_traits::foo::PubPub;
|
LL | use no_method_suggested_traits::qux::PrivPub;
|
-LL | use no_method_suggested_traits::Reexported;
- |
error[E0599]: no method named `method` found for type `char` in the current scope
--> $DIR/no-method-suggested-traits.rs:30:9
|
= 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
--> $DIR/mismatched_trait_impl-2.rs:8:5
|
LL | fn deref(&self) -> &dyn Trait {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Struct) -> &dyn Trait`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Struct) -> &'1 (dyn Trait + '1)`
|
::: $SRC_DIR/core/src/ops/deref.rs:LL:COL
|
LL | fn deref(&self) -> &Self::Target;
- | --------------------------------- expected `fn(&Struct) -> &(dyn Trait + 'static)`
+ | --------------------------------- expected `fn(&'1 Struct) -> &'1 (dyn Trait + 'static)`
|
- = note: expected `fn(&Struct) -> &(dyn Trait + 'static)`
- found `fn(&Struct) -> &dyn Trait`
+ = note: expected `fn(&'1 Struct) -> &'1 (dyn Trait + 'static)`
+ found `fn(&'1 Struct) -> &'1 (dyn Trait + '1)`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
--> $DIR/mismatched_trait_impl.rs:9:5
|
LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
- | ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
+ | ---------------------------------------------- expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
...
LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
|
- = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
- found `fn(&i32, &u32, &u32) -> &u32`
+ = note: expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
+ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
--> $DIR/mismatched_trait_impl.rs:9:5
|
LL | fn foo(&self, x: &'a u32, y: &u32) -> &'a u32;
- | ---------------------------------------------- expected `fn(&i32, &'a u32, &u32) -> &'a u32`
+ | ---------------------------------------------- expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
...
LL | fn foo(&self, x: &u32, y: &'a u32) -> &'a u32 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &u32, &u32) -> &u32`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
|
- = note: expected `fn(&i32, &'a u32, &u32) -> &'a u32`
- found `fn(&i32, &u32, &u32) -> &u32`
+ = note: expected `fn(&'1 i32, &'a u32, &'2 u32) -> &'a u32`
+ found `fn(&'1 i32, &'2 u32, &'3 u32) -> &'3 u32`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
| |
| cannot infer type for type parameter `Q` declared on the associated function `get`
|
- = note: cannot satisfy `String: Borrow<_>`
+ = note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
+ - impl Borrow<str> for String;
+ - impl<T> Borrow<T> for T
+ where T: ?Sized;
error: aborting due to previous error
| |
| cannot infer type
|
- = note: cannot satisfy `String: PartialEq<_>`
+ = note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate:
+ - impl PartialEq for String;
+ - impl<'a, 'b> PartialEq<&'a str> for String;
+ - impl<'a, 'b> PartialEq<Cow<'a, str>> for String;
+ - impl<'a, 'b> PartialEq<str> for String;
error: aborting due to previous error
//~^ 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`.
LL | let _ = <S5<_>>::xxx;
| ^^^^^^^^^^^^ cannot infer type for struct `S5<_>`
|
- = note: cannot satisfy `S5<_>: Foo`
+note: multiple `impl`s satisfying `S5<_>: Foo` found
+ --> $DIR/issue-29147.rs:17:1
+ |
+LL | impl Foo for S5<u32> { fn xxx(&self) {} }
+ | ^^^^^^^^^^^^^^^^^^^^
+LL | impl Foo for S5<u64> { fn xxx(&self) {} }
+ | ^^^^^^^^^^^^^^^^^^^^
note: required by `Foo::xxx`
--> $DIR/issue-29147.rs:10:13
|
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`
// run-fail
// compile-flags: -C opt-level=3
-// min-llvm-version: 11.0
// error-pattern: index out of bounds: the len is 0 but the index is 16777216
// ignore-wasm no panic or subprocess support
// ignore-emscripten no panic or subprocess support
fn main() {
let xs: Vec<u64> = vec![1, 2, 3];
println!("{}", 23u64.test(xs.iter().sum())); //~ ERROR: type annotations needed
+ //~^ ERROR type annotations needed
}
LL | println!("{}", 23u64.test(xs.iter().sum()));
| ^^^^ cannot satisfy `<u64 as Test<_>>::Output == _`
-error: aborting due to previous error
+error[E0283]: type annotations needed
+ --> $DIR/issue-69455.rs:29:26
+ |
+LL | println!("{}", 23u64.test(xs.iter().sum()));
+ | ^^^^ cannot infer type for type parameter `Rhs` declared on the trait `Test`
+ |
+note: multiple `impl`s satisfying `u64: Test<_>` found
+ --> $DIR/issue-69455.rs:11:1
+ |
+LL | impl Test<u32> for u64 {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Test<u64> for u64 {
+ | ^^^^^^^^^^^^^^^^^^^^^^
+help: consider specifying the type argument in the method call
+ |
+LL | println!("{}", 23u64.test(xs.iter().sum::<S>()));
+ | +++++
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0283, E0284.
+For more information about an error, try `rustc --explain E0283`.
let b: [u8; 3] = [0u8; 3];
0u16.foo(b); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
//<u16 as Foo<[(); 3]>>::foo(0u16, b);
}
LL | 0u16.foo(b);
| ^^^ cannot satisfy `<u8 as Element<_>>::Array == [u8; 3]`
-error: aborting due to previous error
+error[E0283]: type annotations needed
+ --> $DIR/issue-69683.rs:30:10
+ |
+LL | 0u16.foo(b);
+ | ^^^ cannot infer type for type parameter `I` declared on the trait `Foo`
+ |
+note: multiple `impl`s satisfying `u8: Element<_>` found
+ --> $DIR/issue-69683.rs:5:1
+ |
+LL | impl<T> Element<()> for T {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl<T: Element<S>, S> Element<[S; 3]> for T {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0284`.
+Some errors have detailed explanations: E0283, E0284.
+For more information about an error, try `rustc --explain E0283`.
fn err() {
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
}
fn arg_pat_closure_err() {
|x| String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
+ //~| ERROR type annotations needed
}
fn local_pat_closure_err() {
fn err_first_arg_pat() {
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
|x: String| x;
}
fn err_second_arg_pat() {
|x: String| x;
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
}
fn err_mid_arg_pat() {
|x: String| x;
|x: String| x;
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
|x: String| x;
|x: String| x;
|x: String| x;
fn err_first_local_pat() {
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
let _ = String::from("x");
}
fn err_second_local_pat() {
let _ = String::from("x");
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
}
fn err_mid_local_pat() {
let _ = String::from("x");
let _ = String::from("x");
String::from("x".as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
let _ = String::from("x");
let _ = String::from("x");
let _ = String::from("x");
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:7:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
error[E0282]: type annotations needed
- --> $DIR/issue-72690.rs:11:6
+ --> $DIR/issue-72690.rs:12:6
|
LL | |x| String::from("x".as_ref());
| ^ consider giving this closure parameter a type
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:12:9
+ |
+LL | |x| String::from("x".as_ref());
+ | ^^^^^^^^^^^^ cannot infer type for reference `&_`
+ |
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
+note: required by `from`
+ --> $SRC_DIR/core/src/convert/mod.rs:LL:COL
+ |
+LL | fn from(_: T) -> Self;
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:12:26
+ |
+LL | |x| String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
error[E0283]: type annotations needed for `&T`
- --> $DIR/issue-72690.rs:15:17
+ --> $DIR/issue-72690.rs:18:17
|
LL | let _ = "x".as_ref();
| - ^^^^^^ cannot infer type for type parameter `T` declared on the trait `AsRef`
| |
| consider giving this pattern the explicit type `&T`, where the type parameter `T` is specified
|
- = note: cannot satisfy `str: AsRef<_>`
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:19:5
+ --> $DIR/issue-72690.rs:22:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:25:5
+ --> $DIR/issue-72690.rs:22:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:29:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:33:5
+ --> $DIR/issue-72690.rs:29:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:38:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:41:5
+ --> $DIR/issue-72690.rs:38:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:47:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:47:5
+ --> $DIR/issue-72690.rs:47:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:54:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed
- --> $DIR/issue-72690.rs:55:5
+ --> $DIR/issue-72690.rs:54:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:63:5
|
LL | String::from("x".as_ref());
| ^^^^^^^^^^^^ cannot infer type for reference `&_`
|
- = note: cannot satisfy `String: From<&_>`
+ = note: multiple `impl`s satisfying `String: From<&_>` found in the `alloc` crate:
+ - impl<> From<&String> for String;
+ - impl<> From<&str> for String;
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
LL | fn from(_: T) -> Self;
| ^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 9 previous errors
+error[E0283]: type annotations needed
+ --> $DIR/issue-72690.rs:63:22
+ |
+LL | String::from("x".as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`:
+ - impl AsRef<OsStr> for str;
+ - impl AsRef<Path> for str;
+ - impl AsRef<[u8]> for str;
+ - impl AsRef<str> for str;
+
+error: aborting due to 18 previous errors
Some errors have detailed explanations: E0282, E0283.
For more information about an error, try `rustc --explain E0282`.
| |_^
help: try to construct one of the enum's variants
|
-LL | let x = A::TupleWithFields(3);
- | ~~~~~~~~~~~~~~~~~~
LL | let x = A::Tuple(3);
| ~~~~~~~~
+LL | let x = A::TupleWithFields(3);
+ | ~~~~~~~~~~~~~~~~~~
error[E0532]: expected tuple struct or tuple variant, found enum `A`
--> $DIR/issue-73427.rs:42:12
| |_^
help: try to match against one of the enum's variants
|
-LL | if let A::TupleWithFields(3) = x { }
- | ~~~~~~~~~~~~~~~~~~
LL | if let A::Tuple(3) = x { }
| ~~~~~~~~
+LL | if let A::TupleWithFields(3) = x { }
+ | ~~~~~~~~~~~~~~~~~~
error: aborting due to 6 previous errors
--- /dev/null
+// check-pass
+
+// RSplit<T, P> previously required T: Clone in order to be Clone
+
+struct NotClone;
+
+fn main() {
+ let elements = [NotClone, NotClone, NotClone];
+ let rsplit = elements.rsplit(|_| false);
+ rsplit.clone();
+}
--> $DIR/lifetime-mismatch-between-trait-and-impl.rs:6:5
|
LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32;
- | ------------------------------------------- expected `fn(&i32, &'a i32) -> &'a i32`
+ | ------------------------------------------- expected `fn(&'1 i32, &'a i32) -> &'a i32`
...
LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&i32, &i32) -> &i32`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 i32, &'1 i32) -> &'1 i32`
|
- = note: expected `fn(&i32, &'a i32) -> &'a i32`
- found `fn(&i32, &i32) -> &i32`
+ = note: expected `fn(&'1 i32, &'a i32) -> &'a i32`
+ found `fn(&'1 i32, &'1 i32) -> &'1 i32`
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
-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
|
-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
|
--- /dev/null
+// run-rustfix
+
+#![allow(unused_macros)]
+
+macro_rules! foo {
+ //~^ ERROR expected `!` after `macro_rules`
+ () => {};
+}
+
+macro_rules! bar {
+ //~^ ERROR expected `!` after `macro_rules`
+ //~^^ ERROR macro names aren't followed by a `!`
+ () => {};
+}
+
+fn main() {}
--- /dev/null
+// run-rustfix
+
+#![allow(unused_macros)]
+
+macro_rules foo {
+ //~^ ERROR expected `!` after `macro_rules`
+ () => {};
+}
+
+macro_rules bar! {
+ //~^ ERROR expected `!` after `macro_rules`
+ //~^^ ERROR macro names aren't followed by a `!`
+ () => {};
+}
+
+fn main() {}
--- /dev/null
+error: expected `!` after `macro_rules`
+ --> $DIR/missing-bang-in-decl.rs:5:1
+ |
+LL | macro_rules foo {
+ | ^^^^^^^^^^^ help: add a `!`: `macro_rules!`
+
+error: expected `!` after `macro_rules`
+ --> $DIR/missing-bang-in-decl.rs:10:1
+ |
+LL | macro_rules bar! {
+ | ^^^^^^^^^^^ help: add a `!`: `macro_rules!`
+
+error: macro names aren't followed by a `!`
+ --> $DIR/missing-bang-in-decl.rs:10:16
+ |
+LL | macro_rules bar! {
+ | ^ help: remove the `!`
+
+error: aborting due to 3 previous errors
+
-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
|
LL | impl<'a> A for (&'static (), &'a ()) {}
| ^ cannot infer type for tuple `(&'static (), &'a ())`
|
- = note: cannot satisfy `(&'static (), &'a ()): A`
+note: multiple `impl`s satisfying `(&'static (), &'a ()): A` found
+ --> $DIR/region-overlap.rs:5:1
+ |
+LL | impl<'a> A for (&'static (), &'a ()) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> A for (&'a (), &'static ()) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `A`
--> $DIR/region-overlap.rs:4:1
|
LL | impl<'a> A for (&'a (), &'static ()) {}
| ^ cannot infer type for tuple `(&'a (), &'static ())`
|
- = note: cannot satisfy `(&'a (), &'static ()): A`
+note: multiple `impl`s satisfying `(&'a (), &'static ()): A` found
+ --> $DIR/region-overlap.rs:5:1
+ |
+LL | impl<'a> A for (&'static (), &'a ()) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> A for (&'a (), &'static ()) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `A`
--> $DIR/region-overlap.rs:4:1
|
// we couldn't infer the type of the vector just based on calling foo()...
let mut x = Vec::new();
//~^ ERROR type annotations needed
- x.foo();
+ x.foo(); //~ ERROR type annotations needed
}
fn m2() {
| |
| consider giving `x` the explicit type `Vec<T>`, where the type parameter `T` is specified
+error[E0283]: type annotations needed
+ --> $DIR/method-ambig-one-trait-unknown-int-type.rs:26:7
+ |
+LL | x.foo();
+ | ^^^ cannot infer type for struct `Vec<_>`
+ |
+note: multiple `impl`s satisfying `Vec<_>: Foo` found
+ --> $DIR/method-ambig-one-trait-unknown-int-type.rs:9:1
+ |
+LL | impl Foo for Vec<usize> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Foo for Vec<isize> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
error[E0308]: mismatched types
--> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20
|
LL | let y: usize = x.foo().try_into().unwrap();
| ++++++++++++++++++++
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
-Some errors have detailed explanations: E0282, E0308.
+Some errors have detailed explanations: E0282, E0283, E0308.
For more information about an error, try `rustc --explain E0282`.
--> $DIR/issue-75361-mismatched-impl.rs:18:3
|
LL | fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType>>;
- | --------------------------------------------------------------------- expected `fn(&T) -> Box<(dyn MyTrait<Item = &T> + 'static)>`
+ | --------------------------------------------------------------------- expected `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
...
LL | fn adjacent_edges(&self) -> Box<dyn MyTrait<Item = &Self::EdgeType> + '_> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&T) -> Box<dyn MyTrait<Item = &T>>`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
|
- = note: expected `fn(&T) -> Box<(dyn MyTrait<Item = &T> + 'static)>`
- found `fn(&T) -> Box<dyn MyTrait<Item = &T>>`
+ = note: expected `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + 'static)>`
+ found `fn(&'1 T) -> Box<(dyn MyTrait<Item = &'1 T> + '1)>`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
--> $DIR/issue-75361-mismatched-impl.rs:12:55
|
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
+// check-pass
+#![feature(type_alias_impl_trait)]
+
+pub trait Trait {
+ type A;
+
+ fn f() -> Self::A;
+}
+
+pub trait Tr2<'a, 'b> {}
+
+pub struct A<T>(T);
+pub trait Tr {
+ type B;
+}
+
+impl<'a, 'b, T: Tr<B = dyn Tr2<'a, 'b>>> Trait for A<T> {
+ type A = impl core::fmt::Debug;
+
+ fn f() -> Self::A {}
+}
+
+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`
|
help: the following are the possible correct uses
|
-LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]
- |
LL | #[rustc_on_unimplemented = "message"]
|
+LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]
+ |
error[E0230]: there is no parameter `C` on trait `BadAnnotation2`
--> $DIR/bad-annotation.rs:22:1
--- /dev/null
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=line,file
+
+fn main() {
+ panic!("column-redacted");
+}
--- /dev/null
+thread 'main' panicked at 'column-redacted', $DIR/location-detail-panic-no-column.rs:6:0
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
--- /dev/null
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=line,column
+
+fn main() {
+ panic!("file-redacted");
+}
--- /dev/null
+thread 'main' panicked at 'file-redacted', <redacted>:6:5
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
--- /dev/null
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=file,column
+
+fn main() {
+ panic!("line-redacted");
+}
--- /dev/null
+thread 'main' panicked at 'line-redacted', $DIR/location-detail-panic-no-line.rs:0:5
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
--- /dev/null
+// run-fail
+// check-run-results
+// compile-flags: -Zlocation-detail=line,column
+
+fn main() {
+ let opt: Option<u32> = None;
+ opt.unwrap();
+}
--- /dev/null
+thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', <redacted>:7:9
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
--- /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
+// 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
+// edition:2021
+#![allow(incomplete_features)]
+#![allow(unreachable_code)]
+#![feature(const_async_blocks)]
+#![feature(inline_const)]
+
+fn main() {
+ match loop {} {
+ const { || {} } => {}, //~ ERROR cannot be used in patterns
+ }
+ match loop {} {
+ const { async {} } => {}, //~ ERROR cannot be used in patterns
+ }
+}
--- /dev/null
+error: `[closure@$DIR/non-structural-match-types.rs:9:17: 9:22]` cannot be used in patterns
+ --> $DIR/non-structural-match-types.rs:9:9
+ |
+LL | const { || {} } => {},
+ | ^^^^^^^^^^^^^^^
+
+error: `impl Future` cannot be used in patterns
+ --> $DIR/non-structural-match-types.rs:12:9
+ |
+LL | const { async {} } => {},
+ | ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
}
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
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 cannot find type `OuterAttr` in this scope
struct S;
-#[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope
- //~| WARN cannot find type `OuterDerive` in this scope
+#[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
+ //~| ERROR cannot find type `OuterDerive` in this scope
//~| WARN this was previously accepted
//~| WARN this was previously accepted
struct Z;
fn inner_block() {
- #[derive(generate_mod::CheckDerive)] //~ WARN cannot find type `FromOutside` in this scope
- //~| WARN cannot find type `OuterDerive` in this scope
+ #[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
+ //~| ERROR cannot find type `OuterDerive` in this scope
//~| WARN this was previously accepted
//~| WARN this was previously accepted
struct InnerZ;
OuterAttr
= note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
--> $DIR/generate-mod.rs:16:10
|
LL | #[derive(generate_mod::CheckDerive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
|
- = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+ = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
--> $DIR/generate-mod.rs:16:10
|
LL | #[derive(generate_mod::CheckDerive)]
|
= 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
--> $DIR/generate-mod.rs:23:14
|
LL | #[derive(generate_mod::CheckDerive)]
|
= 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
--> $DIR/generate-mod.rs:23:14
|
LL | #[derive(generate_mod::CheckDerive)]
|
= 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 4 previous errors; 4 warnings emitted
+error: aborting due to 8 previous errors
For more information about this error, try `rustc --explain E0412`.
Future incompatibility report: Future breakage diagnostic:
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
--> $DIR/generate-mod.rs:16:10
|
LL | #[derive(generate_mod::CheckDerive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
|
- = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+ = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
--> $DIR/generate-mod.rs:16:10
|
LL | #[derive(generate_mod::CheckDerive)]
|
= 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: cannot find type `FromOutside` in this scope
+error: cannot find type `FromOutside` in this scope
--> $DIR/generate-mod.rs:23:14
|
LL | #[derive(generate_mod::CheckDerive)]
|
= 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: cannot find type `OuterDerive` in this scope
+error: cannot find type `OuterDerive` in this scope
--> $DIR/generate-mod.rs:23:14
|
LL | #[derive(generate_mod::CheckDerive)]
|
= 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 #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this warning originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
warning: cannot find type `FromOutside` in this scope
-// check-pass
// aux-build:pin-project-internal-0.4.0.rs
// compile-flags: -Z span-debug
}
struct Foo;
- impl_macros!(Foo); //~ WARN using an old version
+ impl_macros!(Foo); //~ ERROR using an old version
//~| WARN this was previously
arrays!(Foo);
other!(Foo);
}
struct Foo;
- impl_macros!(Foo); //~ WARN using an old version
+ impl_macros!(Foo); //~ ERROR using an old version
//~| WARN this was previously
- arrays!(Foo); //~ WARN using an old version
+ arrays!(Foo); //~ ERROR using an old version
//~| WARN this was previously
other!(Foo);
}
include!("actix-web/src/extract.rs");
struct Foo;
- tuple_from_req!(Foo); //~ WARN using an old version
+ tuple_from_req!(Foo); //~ ERROR using an old version
//~| WARN this was previously
}
include!("actix-web-2.0.0/src/extract.rs");
struct Foo;
- tuple_from_req!(Foo); //~ WARN using an old version
+ tuple_from_req!(Foo); //~ ERROR using an old version
//~| WARN this was previously
}
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
--> $DIR/time-macros-impl/src/lib.rs:5:32
|
LL | #[my_macro] struct One($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:27:5
+ ::: $DIR/group-compat-hack.rs:26:5
|
LL | impl_macros!(Foo);
| ----------------- in this macro invocation
|
- = note: `#[warn(proc_macro_back_compat)]` on by default
+ = note: `#[deny(proc_macro_back_compat)]` 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
- = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
--> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32
|
LL | #[my_macro] struct One($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:44:5
+ ::: $DIR/group-compat-hack.rs:43:5
|
LL | impl_macros!(Foo);
| ----------------- in this macro invocation
= 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
- = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: using an old version of `js-sys`
+error: using an old version of `js-sys`
--> $DIR/js-sys-0.3.17/src/lib.rs:5:32
|
LL | #[my_macro] struct Two($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:46:5
+ ::: $DIR/group-compat-hack.rs:45:5
|
LL | arrays!(Foo);
| ------------ in this macro invocation
= 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: older versions of the `js-sys` crate will stop compiling in future versions of Rust; please update to `js-sys` v0.3.40 or above
- = note: this warning originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
--> $DIR/actix-web/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
- ::: $DIR/group-compat-hack.rs:55:5
+ ::: $DIR/group-compat-hack.rs:54:5
|
LL | tuple_from_req!(Foo);
| -------------------- in this macro invocation
= 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
- = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
--> $DIR/actix-web-2.0.0/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
- ::: $DIR/group-compat-hack.rs:63:5
+ ::: $DIR/group-compat-hack.rs:62:5
|
LL | tuple_from_req!(Foo);
| -------------------- in this macro invocation
= 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
- = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
-warning: 5 warnings emitted
+error: aborting due to 5 previous errors
Future incompatibility report: Future breakage diagnostic:
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
--> $DIR/time-macros-impl/src/lib.rs:5:32
|
LL | #[my_macro] struct One($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:27:5
+ ::: $DIR/group-compat-hack.rs:26:5
|
LL | impl_macros!(Foo);
| ----------------- in this macro invocation
|
- = note: `#[warn(proc_macro_back_compat)]` on by default
+ = note: `#[deny(proc_macro_back_compat)]` 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
- = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: using an old version of `time-macros-impl`
+error: using an old version of `time-macros-impl`
--> $DIR/time-macros-impl-0.1.0/src/lib.rs:5:32
|
LL | #[my_macro] struct One($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:44:5
+ ::: $DIR/group-compat-hack.rs:43:5
|
LL | impl_macros!(Foo);
| ----------------- in this macro invocation
= 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the `time-macros-impl` crate will stop compiling in futures version of Rust. Please update to the latest version of the `time` crate to avoid breakage
- = note: this warning originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `impl_macros` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: using an old version of `js-sys`
+error: using an old version of `js-sys`
--> $DIR/js-sys-0.3.17/src/lib.rs:5:32
|
LL | #[my_macro] struct Two($name);
| ^^^^^
|
- ::: $DIR/group-compat-hack.rs:46:5
+ ::: $DIR/group-compat-hack.rs:45:5
|
LL | arrays!(Foo);
| ------------ in this macro invocation
= 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: older versions of the `js-sys` crate will stop compiling in future versions of Rust; please update to `js-sys` v0.3.40 or above
- = note: this warning originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `arrays` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
--> $DIR/actix-web/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
- ::: $DIR/group-compat-hack.rs:55:5
+ ::: $DIR/group-compat-hack.rs:54:5
|
LL | tuple_from_req!(Foo);
| -------------------- in this macro invocation
= 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
- = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
Future breakage diagnostic:
-warning: using an old version of `actix-web`
+error: using an old version of `actix-web`
--> $DIR/actix-web-2.0.0/src/extract.rs:5:34
|
LL | #[my_macro] struct Three($T);
| ^^
|
- ::: $DIR/group-compat-hack.rs:63:5
+ ::: $DIR/group-compat-hack.rs:62:5
|
LL | tuple_from_req!(Foo);
| -------------------- in this macro invocation
= 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: the version of `actix-web` you are using might stop compiling in future versions of Rust; please update to the latest version of the `actix-web` crate to avoid breakage
- = note: this warning originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `tuple_from_req` (in Nightly builds, run with -Z macro-backtrace for more info)
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:13: 29:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:32: 5:37 (#10) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:30:12: 30:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#14) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#14) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:18: 44:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:46:13: 46:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:39:25: 39:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:39:32: 39:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:48:12: 48:15 (#0) }], span: $DIR/group-compat-hack.rs:39:38: 39:43 (#28) }], span: $DIR/group-compat-hack.rs:39:37: 39:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:39:44: 39:45 (#28) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:55:21: 55:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:63:21: 63:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:71:21: 71:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:33: 5:35 (#43) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:78:21: 78:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:33: 5:35 (#48) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]
-Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.40/src/lib.rs:5:21: 5:27 (#53) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.40/src/lib.rs:5:28: 5:31 (#53) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:84:13: 84:16 (#0) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:32: 5:37 (#53) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:31: 5:38 (#53) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.40/src/lib.rs:5:38: 5:39 (#53) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:26:18: 26:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:32: 5:37 (#10) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:21:25: 21:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:21:32: 21:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:21:38: 21:43 (#14) }], span: $DIR/group-compat-hack.rs:21:37: 21:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:21:44: 21:45 (#14) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:13: 45:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:47:12: 47:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:54:21: 54:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:62:21: 62:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:70:21: 70:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:33: 5:35 (#43) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:77:21: 77:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:33: 5:35 (#48) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }]
+Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.40/src/lib.rs:5:21: 5:27 (#53) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.40/src/lib.rs:5:28: 5:31 (#53) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:83:13: 83:16 (#0) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:32: 5:37 (#53) }], span: $DIR/js-sys-0.3.40/src/lib.rs:5:31: 5:38 (#53) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.40/src/lib.rs:5:38: 5:39 (#53) }]
-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
|
-// check-pass
// aux-build:test-macros.rs
#[macro_use]
extern crate test_macros;
#[derive(Print)]
-enum ProceduralMasqueradeDummyType { //~ WARN using
+enum ProceduralMasqueradeDummyType { //~ ERROR using
//~| WARN this was previously
Input
}
-warning: using `procedural-masquerade` crate
- --> $DIR/issue-73933-procedural-masquerade.rs:8:6
+error: using `procedural-masquerade` crate
+ --> $DIR/issue-73933-procedural-masquerade.rs:7:6
|
LL | enum ProceduralMasqueradeDummyType {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `#[warn(proc_macro_back_compat)]` on by default
+ = note: `#[deny(proc_macro_back_compat)]` 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
-warning: 1 warning emitted
+error: aborting due to previous error
Future incompatibility report: Future breakage diagnostic:
-warning: using `procedural-masquerade` crate
- --> $DIR/issue-73933-procedural-masquerade.rs:8:6
+error: using `procedural-masquerade` crate
+ --> $DIR/issue-73933-procedural-masquerade.rs:7:6
|
LL | enum ProceduralMasqueradeDummyType {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `#[warn(proc_macro_back_compat)]` on by default
+ = note: `#[deny(proc_macro_back_compat)]` 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
= note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "enum",
- span: #0 bytes(100..104),
+ span: #0 bytes(86..90),
},
Ident {
ident: "ProceduralMasqueradeDummyType",
- span: #0 bytes(105..134),
+ span: #0 bytes(91..120),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "Input",
- span: #0 bytes(186..191),
+ span: #0 bytes(173..178),
},
],
- span: #0 bytes(135..193),
+ span: #0 bytes(121..180),
},
]
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
+#![feature(type_alias_impl_trait)]
+
+type PairCoupledTypes: Trait<
+ //~^ ERROR: bounds on `type`s in this context have no effect
+ //~| ERROR: cannot find trait `Trait` in this scope
+ [u32; {
+ static FOO: usize; //~ ERROR: free static item without body
+ }],
+> = impl Trait<
+ //~^ ERROR: cannot find trait `Trait` in this scope
+ [u32; {
+ static FOO: usize; //~ ERROR: free static item without body
+ }],
+>;
+
+fn main() {}
--- /dev/null
+error: bounds on `type`s in this context have no effect
+ --> $DIR/issue-83479.rs:3:24
+ |
+LL | type PairCoupledTypes: Trait<
+ | ________________________^
+LL | |
+LL | |
+LL | | [u32; {
+LL | | static FOO: usize;
+LL | | }],
+LL | | > = impl Trait<
+ | |_^
+
+error: free static item without body
+ --> $DIR/issue-83479.rs:7:9
+ |
+LL | static FOO: usize;
+ | ^^^^^^^^^^^^^^^^^-
+ | |
+ | help: provide a definition for the static: `= <expr>;`
+
+error: free static item without body
+ --> $DIR/issue-83479.rs:12:9
+ |
+LL | static FOO: usize;
+ | ^^^^^^^^^^^^^^^^^-
+ | |
+ | help: provide a definition for the static: `= <expr>;`
+
+error[E0405]: cannot find trait `Trait` in this scope
+ --> $DIR/issue-83479.rs:3:24
+ |
+LL | type PairCoupledTypes: Trait<
+ | ^^^^^ not found in this scope
+
+error[E0405]: cannot find trait `Trait` in this scope
+ --> $DIR/issue-83479.rs:9:10
+ |
+LL | > = impl Trait<
+ | ^^^^^ not found in this scope
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0405`.
--- /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`.
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`
|
-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
|
| 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();
|
help: consider importing one of these items
|
-LL | use std::num::NonZeroU32;
- |
LL | use core::num::NonZeroU32;
|
+LL | use std::num::NonZeroU32;
+ |
error: aborting due to previous error
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
+// Checks that we do not ICE when comparing `Self` to `Pin`
+// edition:2021
+
+struct S;
+
+impl S {
+ fn foo(_: Box<Option<S>>) {}
+ fn bar() {
+ Self::foo(None) //~ ERROR mismatched types
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-90213-expected-boxfuture-self-ice.rs:9:19
+ |
+LL | Self::foo(None)
+ | ^^^^ expected struct `Box`, found enum `Option`
+ |
+ = note: expected struct `Box<Option<S>>`
+ found enum `Option<_>`
+ = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
+help: store this in the heap by calling `Box::new`
+ |
+LL | Self::foo(Box::new(None))
+ | +++++++++ +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /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
+// check-pass
+
+pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
+ <&mut () as Clone>::clone(&s);
+}
+
+fn main() {}
fn main() {
test::<A>();
- //~^ ERROR evaluate(Binder(TraitPredicate(<A as std::marker::Send>), [])) = Ok(EvaluatedToOk)
+ //~^ ERROR evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk)
}
-error: evaluate(Binder(TraitPredicate(<A as std::marker::Send>), [])) = Ok(EvaluatedToOk)
+error: evaluate(Binder(TraitPredicate(<A as std::marker::Send>, polarity:Positive), [])) = Ok(EvaluatedToOk)
--> $DIR/cache-reached-depth-ice.rs:43:5
|
LL | fn test<X: ?Sized + Send>() {}
| ----- 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`
let opt = String::new();
opts.get(opt.as_ref()); //~ ERROR type annotations needed
+ //~^ ERROR type annotations needed
}
fn main() {
| |
| cannot infer type for type parameter `Q` declared on the associated function `get`
|
- = note: cannot satisfy `String: Borrow<_>`
+ = note: multiple `impl`s satisfying `String: Borrow<_>` found in the following crates: `alloc`, `core`:
+ - impl Borrow<str> for String;
+ - impl<T> Borrow<T> for T
+ where T: ?Sized;
error[E0283]: type annotations needed
- --> $DIR/issue-77982.rs:12:44
+ --> $DIR/issue-77982.rs:8:18
+ |
+LL | opts.get(opt.as_ref());
+ | ----^^^^^^--
+ | | |
+ | | cannot infer type for type parameter `T` declared on the trait `AsRef`
+ | this method call resolves to `&T`
+ |
+ = note: multiple `impl`s satisfying `String: AsRef<_>` found in the following crates: `alloc`, `std`:
+ - impl AsRef<OsStr> for String;
+ - impl AsRef<Path> for String;
+ - impl AsRef<[u8]> for String;
+ - impl AsRef<str> for String;
+help: use the fully qualified path for the potential candidates
+ |
+LL | opts.get(<String as AsRef<OsStr>>::as_ref(opt));
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | opts.get(<String as AsRef<Path>>::as_ref(opt));
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | opts.get(<String as AsRef<[u8]>>::as_ref(opt));
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+LL | opts.get(<String as AsRef<str>>::as_ref(opt));
+ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0283]: type annotations needed
+ --> $DIR/issue-77982.rs:13:44
|
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(0u32.into())).collect();
| ^^^^^^^^^ ----------- this method call resolves to `T`
| |
| cannot infer type for type parameter `T` declared on the trait `From`
|
- = note: cannot satisfy `u32: From<_>`
+ = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
+ - impl From<Ipv4Addr> for u32;
+ - impl From<NonZeroU32> for u32;
+ - impl From<bool> for u32;
+ - impl From<char> for u32;
+ and 3 more
note: required by `from`
--> $SRC_DIR/core/src/convert/mod.rs:LL:COL
|
| ^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed for `Box<T>`
- --> $DIR/issue-77982.rs:35:16
+ --> $DIR/issue-77982.rs:36:16
|
LL | let _ = ().foo();
| - ^^^ cannot infer type for type parameter `T` declared on the trait `Foo`
| |
| consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
|
- = note: cannot satisfy `(): Foo<'_, _>`
+note: multiple `impl`s satisfying `(): Foo<'_, _>` found
+ --> $DIR/issue-77982.rs:29:1
+ |
+LL | impl Foo<'static, u32> for () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> Foo<'a, i16> for () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0283]: type annotations needed for `Box<T>`
- --> $DIR/issue-77982.rs:39:19
+ --> $DIR/issue-77982.rs:40:19
|
LL | let _ = (&()).bar();
| - ^^^ cannot infer type for type parameter `T` declared on the trait `Bar`
| |
| consider giving this pattern the explicit type `Box<T>`, where the type parameter `T` is specified
|
- = note: cannot satisfy `&(): Bar<'_, _>`
+note: multiple `impl`s satisfying `&(): Bar<'_, _>` found
+ --> $DIR/issue-77982.rs:32:1
+ |
+LL | impl<'a> Bar<'static, u32> for &'a () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl<'a> Bar<'a, i16> for &'a () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0283`.
// Key is that Vec<First> is "ok" and Third<'_, Ty> is "ok modulo regions":
forward();
- //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
- //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+ //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+ //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
reverse();
- //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
- //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+ //~^ ERROR evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
+ //~| ERROR evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
}
-error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
+error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
|
LL | Vec<First>: Unpin,
LL | forward();
| ^^^^^^^
-error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:59:5
|
LL | Third<'a, Ty>: Unpin,
LL | forward();
| ^^^^^^^
-error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>), [])) = Ok(EvaluatedToOkModuloRegions)
+error: evaluate(Binder(TraitPredicate(<Third<'_, Ty> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOkModuloRegions)
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
|
LL | Third<'a, Ty>: Unpin,
LL | reverse();
| ^^^^^^^
-error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>), [])) = Ok(EvaluatedToOk)
+error: evaluate(Binder(TraitPredicate(<std::vec::Vec<First> as std::marker::Unpin>, polarity:Positive), [])) = Ok(EvaluatedToOk)
--> $DIR/issue-83538-tainted-cache-after-cycle.rs:63:5
|
LL | Vec<First>: Unpin,
fn a() {
test(22, std::default::Default::default());
- //~^ ERROR type annotations needed [E0282]
+ //~^ ERROR type annotations needed
+ //~| ERROR type annotations needed
}
fn main() {}
LL | test(22, std::default::Default::default());
| ^^^^ cannot infer type for type parameter `U` declared on the function `test`
-error: aborting due to previous error
+error[E0283]: type annotations needed
+ --> $DIR/multidispatch-convert-ambig-dest.rs:26:5
+ |
+LL | test(22, std::default::Default::default());
+ | ^^^^ cannot infer type for type parameter `U` declared on the function `test`
+ |
+note: multiple `impl`s satisfying `i32: Convert<_>` found
+ --> $DIR/multidispatch-convert-ambig-dest.rs:8:1
+ |
+LL | impl Convert<i8> for i32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | impl Convert<i16> for i32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `test`
+ --> $DIR/multidispatch-convert-ambig-dest.rs:21:11
+ |
+LL | fn test<T,U>(_: T, _: U)
+ | ---- required by a bound in this
+LL | where T : Convert<U>
+ | ^^^^^^^^^^ required by this bound in `test`
+help: consider specifying the type arguments in the function call
+ |
+LL | test::<T, U>(22, std::default::Default::default());
+ | ++++++++
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0282`.
+Some errors have detailed explanations: E0282, E0283.
+For more information about an error, try `rustc --explain E0282`.
| |
| 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
|
+// check-pass
+
#![feature(negative_impls)]
// aux-build: foreign_trait.rs
trait LocalTrait { }
impl<T: ForeignTrait> LocalTrait for T { }
-impl LocalTrait for String { } //~ ERROR conflicting implementations
+impl LocalTrait for String { }
fn main() { }
+++ /dev/null
-error[E0119]: conflicting implementations of trait `LocalTrait` for type `std::string::String`
- --> $DIR/rely-on-negative-impl-in-coherence.rs:19:1
- |
-LL | impl<T: ForeignTrait> LocalTrait for T { }
- | -------------------------------------- first implementation here
-LL | impl LocalTrait for String { }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::string::String`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0119`.
--> $DIR/param-without-lifetime-constraint.rs:14:5
|
LL | fn get_relation(&self) -> To;
- | ----------------------------- expected `fn(&Article) -> &ProofReader`
+ | ----------------------------- expected `fn(&'1 Article) -> &'2 ProofReader`
...
LL | fn get_relation(&self) -> &ProofReader {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&Article) -> &ProofReader`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Article) -> &'1 ProofReader`
|
- = note: expected `fn(&Article) -> &ProofReader`
- found `fn(&Article) -> &ProofReader`
+ = note: expected `fn(&'1 Article) -> &'2 ProofReader`
+ found `fn(&'1 Article) -> &'1 ProofReader`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
--> $DIR/param-without-lifetime-constraint.rs:10:31
|
--> $DIR/self-without-lifetime-constraint.rs:45:5
|
LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self, &Self>;
- | -------------------------------------------------------------------- expected `fn(ValueRef<'_>) -> Result<(&str, &&str), FromSqlError>`
+ | -------------------------------------------------------------------- expected `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
...
LL | fn column_result(value: ValueRef<'_>) -> FromSqlResult<&str, &&str> {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'_>) -> Result<(&str, &&str), FromSqlError>`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
|
- = note: expected `fn(ValueRef<'_>) -> Result<(&str, &&str), _>`
- found `fn(ValueRef<'_>) -> Result<(&str, &&str), _>`
+ = note: expected `fn(ValueRef<'1>) -> Result<(&'2 str, &'1 &'2 str), FromSqlError>`
+ found `fn(ValueRef<'1>) -> Result<(&'1 str, &'1 &'1 str), FromSqlError>`
help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
--> $DIR/self-without-lifetime-constraint.rs:41:60
|
impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
fn main() {
- 10.dup::<i32>();
+ 10.dup::<i32>(); //~ ERROR type annotations needed
//~^ ERROR this associated function takes 0 generic arguments but 1
- 10.blah::<i32, i32>();
+ 10.blah::<i32, i32>(); //~ ERROR type annotations needed
//~^ ERROR this associated function takes 1 generic argument but 2
(Box::new(10) as Box<dyn bar>).dup();
//~^ ERROR E0038
= note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn bar>>` for `Box<{integer}>`
= note: required by cast to type `Box<dyn bar>`
-error: aborting due to 5 previous errors
+error[E0283]: type annotations needed
+ --> $DIR/test-2.rs:9:8
+ |
+LL | 10.dup::<i32>();
+ | ^^^ cannot infer type for type `{integer}`
+ |
+note: multiple `impl`s satisfying `{integer}: bar` found
+ --> $DIR/test-2.rs:5:1
+ |
+LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
+ | ^^^^^^^^^^^^^^^^
+LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
+ | ^^^^^^^^^^^^^^^^
+
+error[E0283]: type annotations needed
+ --> $DIR/test-2.rs:11:8
+ |
+LL | 10.blah::<i32, i32>();
+ | ^^^^ cannot infer type for type `{integer}`
+ |
+note: multiple `impl`s satisfying `{integer}: bar` found
+ --> $DIR/test-2.rs:5:1
+ |
+LL | impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
+ | ^^^^^^^^^^^^^^^^
+LL | impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
+ | ^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
-Some errors have detailed explanations: E0038, E0107.
+Some errors have detailed explanations: E0038, E0107, E0283.
For more information about an error, try `rustc --explain E0038`.
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
+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`.
| ^^^^ 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>`
| |
| 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
+// Test that the variance computation considers types that
+// appear in const expressions to be invariant.
+
+#![feature(rustc_attrs)]
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait Trait {
+ const Const: usize;
+}
+
+#[rustc_variance]
+struct Foo<T: Trait> { //~ ERROR [o]
+ field: [u8; <T as Trait>::Const]
+}
+
+fn main() { }
--- /dev/null
+error[E0208]: [o]
+ --> $DIR/variance-associated-consts.rs:13:1
+ |
+LL | / struct Foo<T: Trait> {
+LL | | field: [u8; <T as Trait>::Const]
+LL | | }
+ | |_^
+
+error: aborting due to previous error
+
#[derive(Debug, serde::Deserialize)]
struct ManifestTargetPackage {
- available: bool,
url: Option<String>,
hash: Option<String>,
xz_url: Option<String>,
-Subproject commit 7fbbf4e8f23e3c24b8afff541dcb17e53eb5ff88
+Subproject commit 6c1bc24b8b49d4bc965f67d7037906dc199c72b7
[`fn_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_address_comparisons
[`fn_params_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_params_excessive_bools
[`fn_to_numeric_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast
+[`fn_to_numeric_cast_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_any
[`fn_to_numeric_cast_with_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#fn_to_numeric_cast_with_truncation
[`for_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_kv_map
[`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
[`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy
[`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref
+[`format_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#format_in_format_args
[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect
[`from_over_into`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into
[`from_str_radix_10`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_str_radix_10
[`match_result_ok`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_result_ok
[`match_same_arms`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms
[`match_single_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_single_binding
+[`match_str_case_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_str_case_mismatch
[`match_wild_err_arm`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wild_err_arm
[`match_wildcard_for_single_variants`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_wildcard_for_single_variants
[`maybe_infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#maybe_infinite_iter
[`new_ret_no_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_ret_no_self
[`new_without_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#new_without_default
[`no_effect`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect
+[`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding
[`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal
[`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions
[`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
[`to_digit_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_digit_is_some
[`to_string_in_display`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_display
+[`to_string_in_format_args`]: https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args
[`todo`]: https://rust-lang.github.io/rust-clippy/master/index.html#todo
[`too_many_arguments`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_arguments
[`too_many_lines`]: https://rust-lang.github.io/rust-clippy/master/index.html#too_many_lines
[`toplevel_ref_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#toplevel_ref_arg
+[`trailing_empty_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#trailing_empty_array
[`trait_duplication_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#trait_duplication_in_bounds
[`transmute_bytes_to_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_bytes_to_str
[`transmute_float_to_int`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_float_to_int
[`transmute_int_to_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_bool
[`transmute_int_to_char`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_char
[`transmute_int_to_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_int_to_float
+[`transmute_num_to_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_num_to_bytes
[`transmute_ptr_to_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ptr
[`transmute_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref
[`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts
[`try_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#try_err
[`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity
[`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds
+[`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks
[`undropped_manually_drops`]: https://rust-lang.github.io/rust-clippy/master/index.html#undropped_manually_drops
[`unicode_not_nfc`]: https://rust-lang.github.io/rust-clippy/master/index.html#unicode_not_nfc
[`unimplemented`]: https://rust-lang.github.io/rust-clippy/master/index.html#unimplemented
[`uninit_assumed_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#uninit_assumed_init
+[`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_return_expecting_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#unit_return_expecting_ord
[package]
name = "clippy"
-version = "0.1.57"
+version = "0.1.58"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
[dependencies]
bytecount = "0.6"
clap = "2.33"
+indoc = "1.0"
itertools = "0.10"
opener = "0.5"
regex = "1.5"
matches.value_of("pass"),
matches.value_of("name"),
matches.value_of("category"),
+ matches.is_present("msrv"),
) {
Ok(_) => update_lints::run(update_lints::UpdateMode::Change),
Err(e) => eprintln!("Unable to create lint: {}", e),
"internal_warn",
])
.takes_value(true),
+ )
+ .arg(
+ Arg::with_name("msrv")
+ .long("msrv")
+ .help("Add MSRV config code to the lint"),
),
)
.subcommand(
use crate::clippy_project_root;
+use indoc::indoc;
use std::fs::{self, OpenOptions};
use std::io::prelude::*;
use std::io::{self, ErrorKind};
/// # Errors
///
/// This function errors out if the files couldn't be created or written to.
-pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>) -> io::Result<()> {
+pub fn create(pass: Option<&str>, lint_name: Option<&str>, category: Option<&str>, msrv: bool) -> io::Result<()> {
let lint = LintData {
pass: pass.expect("`pass` argument is validated by clap"),
name: lint_name.expect("`name` argument is validated by clap"),
project_root: clippy_project_root(),
};
- create_lint(&lint).context("Unable to create lint implementation")?;
+ create_lint(&lint, msrv).context("Unable to create lint implementation")?;
create_test(&lint).context("Unable to create a test for the new lint")
}
-fn create_lint(lint: &LintData<'_>) -> io::Result<()> {
- let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass {
- "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
- "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"),
- _ => {
- unreachable!("`pass_type` should only ever be `early` or `late`!");
- },
- };
-
- let camel_case_name = to_camel_case(lint.name);
- let lint_contents = get_lint_file_contents(
- pass_type,
- pass_lifetimes,
- lint.name,
- &camel_case_name,
- lint.category,
- pass_import,
- context_import,
- );
+fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
+ let lint_contents = get_lint_file_contents(lint, enable_msrv);
let lint_path = format!("clippy_lints/src/{}.rs", lint.name);
write_file(lint.project_root.join(&lint_path), lint_contents.as_bytes())
fn get_test_file_contents(lint_name: &str, header_commands: Option<&str>) -> String {
let mut contents = format!(
- "#![warn(clippy::{})]
+ indoc! {"
+ #![warn(clippy::{})]
-fn main() {{
- // test code goes here
-}}
-",
+ fn main() {{
+ // test code goes here
+ }}
+ "},
lint_name
);
fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
format!(
- r#"
-# {}
+ indoc! {r#"
+ # {}
-[package]
-name = "{}"
-version = "0.1.0"
-publish = false
+ [package]
+ name = "{}"
+ version = "0.1.0"
+ publish = false
-[workspace]
-"#,
+ [workspace]
+ "#},
hint, lint_name
)
}
-fn get_lint_file_contents(
- pass_type: &str,
- pass_lifetimes: &str,
- lint_name: &str,
- camel_case_name: &str,
- category: &str,
- pass_import: &str,
- context_import: &str,
-) -> String {
- format!(
- "use rustc_lint::{{{type}, {context_import}}};
-use rustc_session::{{declare_lint_pass, declare_tool_lint}};
-{pass_import}
-
-declare_clippy_lint! {{
- /// ### What it does
- ///
- /// ### Why is this bad?
- ///
- /// ### Example
- /// ```rust
- /// // example code where clippy issues a warning
- /// ```
- /// Use instead:
- /// ```rust
- /// // example code which does not raise clippy warning
- /// ```
- pub {name_upper},
- {category},
- \"default lint description\"
-}}
-
-declare_lint_pass!({name_camel} => [{name_upper}]);
-
-impl {type}{lifetimes} for {name_camel} {{}}
-",
- type=pass_type,
- lifetimes=pass_lifetimes,
- name_upper=lint_name.to_uppercase(),
- name_camel=camel_case_name,
- category=category,
- pass_import=pass_import,
- context_import=context_import
- )
+fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
+ let mut result = String::new();
+
+ let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass {
+ "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"),
+ "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"),
+ _ => {
+ unreachable!("`pass_type` should only ever be `early` or `late`!");
+ },
+ };
+
+ 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();
+
+ result.push_str(&if enable_msrv {
+ format!(
+ indoc! {"
+ use clippy_utils::msrvs;
+ {pass_import}
+ use rustc_lint::{{{context_import}, {pass_type}, LintContext}};
+ use rustc_semver::RustcVersion;
+ use rustc_session::{{declare_tool_lint, impl_lint_pass}};
+
+ "},
+ pass_type = pass_type,
+ pass_import = pass_import,
+ context_import = context_import,
+ )
+ } else {
+ format!(
+ indoc! {"
+ {pass_import}
+ use rustc_lint::{{{context_import}, {pass_type}}};
+ use rustc_session::{{declare_lint_pass, declare_tool_lint}};
+
+ "},
+ pass_import = pass_import,
+ pass_type = pass_type,
+ context_import = context_import
+ )
+ });
+
+ result.push_str(&format!(
+ indoc! {"
+ declare_clippy_lint! {{
+ /// ### What it does
+ ///
+ /// ### Why is this bad?
+ ///
+ /// ### Example
+ /// ```rust
+ /// // example code where clippy issues a warning
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// // example code which does not raise clippy warning
+ /// ```
+ pub {name_upper},
+ {category},
+ \"default lint description\"
+ }}
+ "},
+ name_upper = name_upper,
+ category = category,
+ ));
+
+ result.push_str(&if enable_msrv {
+ format!(
+ indoc! {"
+ pub struct {name_camel} {{
+ msrv: Option<RustcVersion>,
+ }}
+
+ impl {name_camel} {{
+ #[must_use]
+ pub fn new(msrv: Option<RustcVersion>) -> Self {{
+ Self {{ msrv }}
+ }}
+ }}
+
+ impl_lint_pass!({name_camel} => [{name_upper}]);
+
+ impl {pass_type}{pass_lifetimes} for {name_camel} {{
+ 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 {
+ format!(
+ indoc! {"
+ 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,
+ )
+ });
+
+ result
}
#[test]
Lint::new("should_assert_eq2", "group2", "abc", None, "module_name"),
];
let expected = vec![
- format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK.to_string()),
- format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK.to_string()),
+ format!("[`should_assert_eq`]: {}#should_assert_eq", DOCS_LINK),
+ format!("[`should_assert_eq2`]: {}#should_assert_eq2", DOCS_LINK),
];
assert_eq!(expected, gen_changelog_lint_list(lints.iter()));
}
[package]
name = "clippy_lints"
-version = "0.1.57"
+version = "0.1.58"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+
+use super::FN_TO_NUMERIC_CAST_ANY;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
+ // We allow casts from any function type to any function type.
+ match cast_to.kind() {
+ ty::FnDef(..) | ty::FnPtr(..) => return,
+ _ => { /* continue to checks */ },
+ }
+
+ match cast_from.kind() {
+ ty::FnDef(..) | ty::FnPtr(_) => {
+ let mut applicability = Applicability::MaybeIncorrect;
+ let from_snippet = snippet_with_applicability(cx, cast_expr.span, "..", &mut applicability);
+
+ span_lint_and_sugg(
+ cx,
+ FN_TO_NUMERIC_CAST_ANY,
+ expr.span,
+ &format!("casting function pointer `{}` to `{}`", from_snippet, cast_to),
+ "did you mean to invoke the function?",
+ format!("{}() as {}", from_snippet, cast_to),
+ applicability,
+ );
+ },
+ _ => {},
+ }
+}
mod cast_sign_loss;
mod char_lit_as_u8;
mod fn_to_numeric_cast;
+mod fn_to_numeric_cast_any;
mod fn_to_numeric_cast_with_truncation;
mod ptr_as_ptr;
mod unnecessary_cast;
"casting a function pointer to a numeric type not wide enough to store the address"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for casts of a function pointer to any integer type.
+ ///
+ /// ### Why is this bad?
+ /// Casting a function pointer to an integer can have surprising results and can occur
+ /// accidentally if parantheses are omitted from a function call. If you aren't doing anything
+ /// low-level with function pointers then you can opt-out of casting functions to integers in
+ /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
+ /// pointer casts in your code.
+ ///
+ /// ### Example
+ /// ```rust
+ /// // Bad: fn1 is cast as `usize`
+ /// fn fn1() -> u16 {
+ /// 1
+ /// };
+ /// let _ = fn1 as usize;
+ ///
+ /// // Good: maybe you intended to call the function?
+ /// fn fn2() -> u16 {
+ /// 1
+ /// };
+ /// let _ = fn2() as usize;
+ ///
+ /// // Good: maybe you intended to cast it to a function type?
+ /// fn fn3() -> u16 {
+ /// 1
+ /// }
+ /// let _ = fn3 as fn() -> u16;
+ /// ```
+ pub FN_TO_NUMERIC_CAST_ANY,
+ restriction,
+ "casting a function pointer to any integer type"
+}
+
declare_clippy_lint! {
/// ### What it does
/// Checks for casts of `&T` to `&mut T` anywhere in the code.
CAST_REF_TO_MUT,
CAST_PTR_ALIGNMENT,
UNNECESSARY_CAST,
+ FN_TO_NUMERIC_CAST_ANY,
FN_TO_NUMERIC_CAST,
FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
CHAR_LIT_AS_U8,
return;
}
+ fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, 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) {
} else {
sm.stmt_span(block.stmts[block.stmts.len() - end_stmts].span, block.span)
};
- let moved_end = block
- .expr
- .map_or_else(
- || sm.stmt_span(block.stmts[block.stmts.len() - 1].span, block.span),
- |expr| expr.span.source_callsite(),
- );
+ let moved_end = block.expr.map_or_else(
+ || sm.stmt_span(block.stmts[block.stmts.len() - 1].span, block.span),
+ |expr| expr.span.source_callsite(),
+ );
let moved_span = moved_start.to(moved_end);
let moved_snipped = reindent_multiline(snippet(cx, moved_span, "_"), true, None);
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::snippet_with_macro_callsite;
+use clippy_utils::ty::{has_drop, is_copy};
use clippy_utils::{any_parent_is_automatically_derived, contains_name, in_macro, match_def_path, paths};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
.fields
.iter()
.all(|field| field.vis.is_accessible_from(module_did, cx.tcx));
+ let all_fields_are_copy = variant
+ .fields
+ .iter()
+ .all(|field| {
+ is_copy(cx, cx.tcx.type_of(field.did))
+ });
+ if !has_drop(cx, binding_type) || all_fields_are_copy;
then {
(local, variant, ident.name, binding_type, expr.span)
} else {
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::span_lint_and_then;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxHashMap;
use rustc_hir::{
def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, TraitBoundModifier, Ty, TyKind, UseKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
+
+use crate::utils::conf;
declare_clippy_lint! {
/// ### What it does
/// An example clippy.toml configuration:
/// ```toml
/// # clippy.toml
- /// disallowed-types = ["std::collections::BTreeMap"]
+ /// disallowed-types = [
+ /// # Can use a string as the path of the disallowed type.
+ /// "std::collections::BTreeMap",
+ /// # Can also use an inline table with a `path` key.
+ /// { path = "std::net::TcpListener" },
+ /// # When using an inline table, can add a `reason` for why the type
+ /// # is disallowed.
+ /// { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
+ /// ]
/// ```
///
/// ```rust,ignore
}
#[derive(Clone, Debug)]
pub struct DisallowedType {
- disallowed: FxHashSet<Vec<Symbol>>,
- def_ids: FxHashSet<DefId>,
- prim_tys: FxHashSet<PrimTy>,
+ conf_disallowed: Vec<conf::DisallowedType>,
+ def_ids: FxHashMap<DefId, Option<String>>,
+ prim_tys: FxHashMap<PrimTy, Option<String>>,
}
impl DisallowedType {
- pub fn new(disallowed: &FxHashSet<String>) -> Self {
+ pub fn new(conf_disallowed: Vec<conf::DisallowedType>) -> Self {
Self {
- disallowed: disallowed
- .iter()
- .map(|s| s.split("::").map(Symbol::intern).collect::<Vec<_>>())
- .collect(),
- def_ids: FxHashSet::default(),
- prim_tys: FxHashSet::default(),
+ conf_disallowed,
+ def_ids: FxHashMap::default(),
+ prim_tys: FxHashMap::default(),
}
}
fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
match res {
Res::Def(_, did) => {
- if self.def_ids.contains(did) {
- emit(cx, &cx.tcx.def_path_str(*did), span);
+ if let Some(reason) = self.def_ids.get(did) {
+ emit(cx, &cx.tcx.def_path_str(*did), span, reason.as_deref());
}
},
Res::PrimTy(prim) => {
- if self.prim_tys.contains(prim) {
- emit(cx, prim.name_str(), span);
+ if let Some(reason) = self.prim_tys.get(prim) {
+ emit(cx, prim.name_str(), span, reason.as_deref());
}
},
_ => {},
impl<'tcx> LateLintPass<'tcx> for DisallowedType {
fn check_crate(&mut self, cx: &LateContext<'_>) {
- for path in &self.disallowed {
- let segs = path.iter().map(ToString::to_string).collect::<Vec<_>>();
- match clippy_utils::path_to_res(cx, &segs.iter().map(String::as_str).collect::<Vec<_>>()) {
+ for conf in &self.conf_disallowed {
+ let (path, reason) = match conf {
+ conf::DisallowedType::Simple(path) => (path, None),
+ conf::DisallowedType::WithReason { path, reason } => (
+ path,
+ reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)),
+ ),
+ };
+ let segs: Vec<_> = path.split("::").collect();
+ match clippy_utils::path_to_res(cx, &segs) {
Res::Def(_, id) => {
- self.def_ids.insert(id);
+ self.def_ids.insert(id, reason);
},
Res::PrimTy(ty) => {
- self.prim_tys.insert(ty);
+ self.prim_tys.insert(ty, reason);
},
_ => {},
}
}
}
-fn emit(cx: &LateContext<'_>, name: &str, span: Span) {
- span_lint(
+fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
+ span_lint_and_then(
cx,
DISALLOWED_TYPE,
span,
&format!("`{}` is not allowed according to config", name),
+ |diag| {
+ if let Some(reason) = reason {
+ diag.note(reason);
+ }
+ },
);
}
+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::ty::{implements_trait, is_type_diagnostic_item};
if !cx.access_levels.is_exported(def_id) {
return; // Private functions do not require doc comments
}
+
+ // do not lint if any parent has `#[doc(hidden)]` attribute (#7347)
+ if cx
+ .tcx
+ .hir()
+ .parent_iter(cx.tcx.hir().local_def_id_to_hir_id(def_id))
+ .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id)))
+ {
+ return;
+ }
+
if !headers.safety && sig.header.unsafety == hir::Unsafety::Unsafe {
span_lint(
cx,
use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then};
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of};
+use clippy_utils::{
+ ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, in_macro, is_expn_of, is_in_test_function,
+};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind};
if macro_args.len() == 2;
let (lhs, rhs) = (macro_args[0], macro_args[1]);
if eq_expr_value(cx, lhs, rhs);
-
+ if !is_in_test_function(cx.tcx, e.hir_id);
then {
span_lint(
cx,
if macro_with_not_op(&left.kind) || macro_with_not_op(&right.kind) {
return;
}
- if is_useless_with_eq_exprs(op.node.into()) && eq_expr_value(cx, left, right) {
+ if is_useless_with_eq_exprs(op.node.into())
+ && eq_expr_value(cx, left, right)
+ && !is_in_test_function(cx.tcx, e.hir_id)
+ {
span_lint(
cx,
EQ_OP,
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::implements_trait;
use if_chain::if_chain;
use rustc_errors::Applicability;
let pat_str = match pat.kind {
PatKind::Struct(..) => format!(
"({})",
- snippet_with_applicability(cx, pat.span, "..", &mut applicability),
+ snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0,
),
- _ => snippet_with_applicability(cx, pat.span, "..", &mut applicability).to_string(),
+ _ => snippet_with_context(cx, pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(),
};
span_lint_and_sugg(
cx,
"try",
format!(
"{} == {}",
- snippet_with_applicability(cx, exp.span, "..", &mut applicability),
+ snippet_with_context(cx, exp.span, expr.span.ctxt(), "..", &mut applicability).0,
pat_str,
),
applicability,
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher::FormatExpn;
-use clippy_utils::last_path_segment;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, QPath};
+use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
ty::Str => true,
_ => false,
};
- if format_args.args.iter().all(is_display_arg);
- if format_args.fmt_expr.map_or(true, check_unformatted);
+ if let Some(args) = format_args.args();
+ if args.iter().all(|arg| arg.is_display() && !arg.has_string_formatting());
then {
let is_new_string = match value.kind {
ExprKind::Binary(..) => true,
applicability,
);
}
-
-fn is_display_arg(expr: &Expr<'_>) -> bool {
- if_chain! {
- if let ExprKind::Call(_, [_, fmt]) = expr.kind;
- if let ExprKind::Path(QPath::Resolved(_, path)) = fmt.kind;
- if let [.., t, _] = path.segments;
- if t.ident.name == sym::Display;
- then { true } else { false }
- }
-}
-
-/// Checks if the expression matches
-/// ```rust,ignore
-/// &[_ {
-/// format: _ {
-/// width: _::Implied,
-/// precision: _::Implied,
-/// ...
-/// },
-/// ...,
-/// }]
-/// ```
-fn check_unformatted(expr: &Expr<'_>) -> bool {
- if_chain! {
- if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
- if let ExprKind::Array([expr]) = expr.kind;
- // struct `core::fmt::rt::v1::Argument`
- if let ExprKind::Struct(_, fields, _) = expr.kind;
- if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
- // struct `core::fmt::rt::v1::FormatSpec`
- if let ExprKind::Struct(_, fields, _) = format_field.expr.kind;
- if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym::precision);
- if let ExprKind::Path(ref precision_path) = precision_field.expr.kind;
- if last_path_segment(precision_path).ident.name == sym::Implied;
- if let Some(width_field) = fields.iter().find(|f| f.ident.name == sym::width);
- if let ExprKind::Path(ref width_qpath) = width_field.expr.kind;
- if last_path_segment(width_qpath).ident.name == sym::Implied;
- then {
- return true;
- }
- }
-
- false
-}
--- /dev/null
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::higher::{FormatArgsArg, FormatArgsExpn, FormatExpn};
+use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::implements_trait;
+use clippy_utils::{is_diag_trait_item, match_def_path, paths};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment};
+use rustc_middle::ty::Ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, BytePos, ExpnData, ExpnKind, Span, Symbol};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects `format!` within the arguments of another macro that does
+ /// formatting such as `format!` itself, `write!` or `println!`. Suggests
+ /// inlining the `format!` call.
+ ///
+ /// ### Why is this bad?
+ /// The recommended code is both shorter and avoids a temporary allocation.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::panic::Location;
+ /// println!("error: {}", format!("something failed at {}", Location::caller()));
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::panic::Location;
+ /// println!("error: something failed at {}", Location::caller());
+ /// ```
+ pub FORMAT_IN_FORMAT_ARGS,
+ perf,
+ "`format!` used in a macro that does formatting"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string)
+ /// applied to a type that implements [`Display`](https://doc.rust-lang.org/std/fmt/trait.Display.html)
+ /// in a macro that does formatting.
+ ///
+ /// ### Why is this bad?
+ /// Since the type implements `Display`, the use of `to_string` is
+ /// unnecessary.
+ ///
+ /// ### Example
+ /// ```rust
+ /// # use std::panic::Location;
+ /// println!("error: something failed at {}", Location::caller().to_string());
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # use std::panic::Location;
+ /// println!("error: something failed at {}", Location::caller());
+ /// ```
+ pub TO_STRING_IN_FORMAT_ARGS,
+ perf,
+ "`to_string` applied to a type that implements `Display` in format args"
+}
+
+declare_lint_pass!(FormatArgs => [FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS]);
+
+const FORMAT_MACRO_PATHS: &[&[&str]] = &[
+ &paths::FORMAT_ARGS_MACRO,
+ &paths::ASSERT_EQ_MACRO,
+ &paths::ASSERT_MACRO,
+ &paths::ASSERT_NE_MACRO,
+ &paths::EPRINT_MACRO,
+ &paths::EPRINTLN_MACRO,
+ &paths::PRINT_MACRO,
+ &paths::PRINTLN_MACRO,
+ &paths::WRITE_MACRO,
+ &paths::WRITELN_MACRO,
+];
+
+const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[sym::format_macro, sym::std_panic_macro];
+
+impl<'tcx> LateLintPass<'tcx> for FormatArgs {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if_chain! {
+ if let Some(format_args) = FormatArgsExpn::parse(expr);
+ let expr_expn_data = expr.span.ctxt().outer_expn_data();
+ let outermost_expn_data = outermost_expn_data(expr_expn_data);
+ if let Some(macro_def_id) = outermost_expn_data.macro_def_id;
+ if FORMAT_MACRO_PATHS
+ .iter()
+ .any(|path| match_def_path(cx, macro_def_id, path))
+ || FORMAT_MACRO_DIAG_ITEMS
+ .iter()
+ .any(|diag_item| cx.tcx.is_diagnostic_item(*diag_item, macro_def_id));
+ if let ExpnKind::Macro(_, name) = outermost_expn_data.kind;
+ if let Some(args) = format_args.args();
+ then {
+ for (i, arg) in args.iter().enumerate() {
+ if !arg.is_display() {
+ continue;
+ }
+ if arg.has_string_formatting() {
+ continue;
+ }
+ if is_aliased(&args, i) {
+ continue;
+ }
+ check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg);
+ check_to_string_in_format_args(cx, name, arg);
+ }
+ }
+ }
+ }
+}
+
+fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
+ if expn_data.call_site.from_expansion() {
+ outermost_expn_data(expn_data.call_site.ctxt().outer_expn_data())
+ } else {
+ expn_data
+ }
+}
+
+fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &FormatArgsArg<'_>) {
+ if_chain! {
+ if FormatExpn::parse(arg.value).is_some();
+ if !arg.value.span.ctxt().outer_expn_data().call_site.from_expansion();
+ then {
+ span_lint_and_then(
+ cx,
+ FORMAT_IN_FORMAT_ARGS,
+ trim_semicolon(cx, call_site),
+ &format!("`format!` in `{}!` args", name),
+ |diag| {
+ diag.help(&format!(
+ "combine the `format!(..)` arguments with the outer `{}!(..)` call",
+ name
+ ));
+ diag.help("or consider changing `format!` to `format_args!`");
+ },
+ );
+ }
+ }
+}
+
+fn check_to_string_in_format_args<'tcx>(cx: &LateContext<'tcx>, name: Symbol, arg: &FormatArgsArg<'tcx>) {
+ let value = arg.value;
+ if_chain! {
+ if !value.span.from_expansion();
+ if let ExprKind::MethodCall(_, _, [receiver], _) = value.kind;
+ if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(value.hir_id);
+ if is_diag_trait_item(cx, method_def_id, sym::ToString);
+ let receiver_ty = cx.typeck_results().expr_ty(receiver);
+ if let Some(display_trait_id) = cx.tcx.get_diagnostic_item(sym::Display);
+ if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
+ then {
+ let (n_needed_derefs, target) = count_needed_derefs(
+ receiver_ty,
+ cx.typeck_results().expr_adjustments(receiver).iter(),
+ );
+ if implements_trait(cx, target, display_trait_id, &[]) {
+ if n_needed_derefs == 0 {
+ span_lint_and_sugg(
+ cx,
+ TO_STRING_IN_FORMAT_ARGS,
+ value.span.with_lo(receiver.span.hi()),
+ &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
+ "remove this",
+ String::new(),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ span_lint_and_sugg(
+ cx,
+ TO_STRING_IN_FORMAT_ARGS,
+ value.span,
+ &format!("`to_string` applied to a type that implements `Display` in `{}!` args", name),
+ "use this",
+ format!("{:*>width$}{}", "", receiver_snippet, width = n_needed_derefs),
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+ }
+ }
+}
+
+// Returns true if `args[i]` "refers to" or "is referred to by" another argument.
+fn is_aliased(args: &[FormatArgsArg<'_>], i: usize) -> bool {
+ let value = args[i].value;
+ args.iter()
+ .enumerate()
+ .any(|(j, arg)| i != j && std::ptr::eq(value, arg.value))
+}
+
+fn trim_semicolon(cx: &LateContext<'_>, span: Span) -> Span {
+ snippet_opt(cx, span).map_or(span, |snippet| {
+ let snippet = snippet.trim_end_matches(';');
+ span.with_hi(span.lo() + BytePos(u32::try_from(snippet.len()).unwrap()))
+ })
+}
+
+fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>)
+where
+ I: Iterator<Item = &'tcx Adjustment<'tcx>>,
+{
+ let mut n_total = 0;
+ let mut n_needed = 0;
+ loop {
+ if let Some(Adjustment {
+ kind: Adjust::Deref(overloaded_deref),
+ target,
+ }) = iter.next()
+ {
+ n_total += 1;
+ if overloaded_deref.is_some() {
+ n_needed = n_total;
+ }
+ ty = target;
+ } else {
+ return (n_needed, ty);
+ }
+ }
+}
declare_clippy_lint! {
/// ### What it does
- /// Checks for a [`#[must_use]`] attribute on
+ /// Checks for a `#[must_use]` attribute on
/// unit-returning functions and methods.
///
- /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
- ///
/// ### Why is this bad?
/// Unit values are useless. The attribute is likely
/// a remnant of a refactoring that removed the return type.
declare_clippy_lint! {
/// ### What it does
- /// Checks for a [`#[must_use]`] attribute without
+ /// Checks for a `#[must_use]` attribute without
/// further information on functions and methods that return a type already
/// marked as `#[must_use]`.
///
- /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
- ///
/// ### Why is this bad?
/// The attribute isn't needed. Not using the result
/// will already be reported. Alternatively, one can add some text to the
declare_clippy_lint! {
/// ### What it does
/// Checks for public functions that have no
- /// [`#[must_use]`] attribute, but return something not already marked
+ /// `#[must_use]` attribute, but return something not already marked
/// must-use, have no mutable arg and mutate no statics.
///
- /// [`#[must_use]`]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
- ///
/// ### Why is this bad?
/// Not bad at all, this lint just shows places where
/// you could add the attribute.
&& constant_simple(cx, cx.typeck_results(), left) == Some(Constant::Int(1))
}
-#[allow(clippy::cast_possible_wrap)]
fn check(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span) {
if let Some(Constant::Int(v)) = constant_simple(cx, cx.typeck_results(), e) {
let check = match *cx.typeck_results().expr_ty(e).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().to_string())
+ 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().to_string())
+ format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par())
};
span_lint_and_sugg(
return;
}
if_chain! {
- if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
+ if let Some(higher::If { cond, then, r#else: None }) = higher::If::hir(expr);
// Check if the conditional expression is a binary operation
if let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind;
item.span,
&format!(
"type `{}` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display`",
- self_type.to_string()
+ self_type
),
None,
- &format!("remove the inherent method from type `{}`", self_type.to_string()),
+ &format!("remove the inherent method from type `{}`", self_type),
);
} else {
span_lint_and_help(
item.span,
&format!(
"implementation of inherent method `to_string(&self) -> String` for type `{}`",
- self_type.to_string()
+ self_type
),
None,
- &format!("implement trait `Display` for type `{}` instead", self_type.to_string()),
+ &format!("implement trait `Display` for type `{}` instead", self_type),
);
}
}
declare_clippy_lint! {
/// ### What it does
- /// Checks for `let _ = <expr>`
- /// where expr is #[must_use]
+ /// Checks for `let _ = <expr>` where expr is `#[must_use]`
///
/// ### Why is this bad?
- /// It's better to explicitly
- /// handle the value of a #[must_use] expr
+ /// It's better to explicitly handle the value of a `#[must_use]`
+ /// expr
///
/// ### Example
/// ```rust
LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS),
LintId::of(float_literal::EXCESSIVE_PRECISION),
LintId::of(format::USELESS_FORMAT),
+ LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
+ LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
LintId::of(formatting::POSSIBLE_MISSING_COMMA),
LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING),
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
LintId::of(match_result_ok::MATCH_RESULT_OK),
+ LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
LintId::of(matches::MATCH_AS_REF),
LintId::of(matches::MATCH_LIKE_MATCHES_MACRO),
LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
+ LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
LintId::of(transmute::WRONG_TRANSMUTE),
LintId::of(types::VEC_BOX),
LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
LintId::of(unicode::INVISIBLE_CHARACTERS),
+ LintId::of(uninit_vec::UNINIT_VEC),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_ARG),
LintId::of(unit_types::UNIT_CMP),
LintId::of(transmute::TRANSMUTE_INT_TO_BOOL),
LintId::of(transmute::TRANSMUTE_INT_TO_CHAR),
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
+ LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
LintId::of(types::BORROWED_BOX),
LintId::of(types::TYPE_COMPLEXITY),
LintId::of(loops::ITER_NEXT_LOOP),
LintId::of(loops::NEVER_LOOP),
LintId::of(loops::WHILE_IMMUTABLE_CONDITION),
+ LintId::of(match_str_case_mismatch::MATCH_STR_CASE_MISMATCH),
LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
LintId::of(methods::CLONE_DOUBLE_REF),
LintId::of(methods::ITERATOR_STEP_BY_ZERO),
LintId::of(transmuting_null::TRANSMUTING_NULL),
LintId::of(undropped_manually_drops::UNDROPPED_MANUALLY_DROPS),
LintId::of(unicode::INVISIBLE_CHARACTERS),
+ LintId::of(uninit_vec::UNINIT_VEC),
LintId::of(unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD),
LintId::of(unit_types::UNIT_CMP),
LintId::of(unnamed_address::FN_ADDRESS_COMPARISONS),
casts::CAST_SIGN_LOSS,
casts::CHAR_LIT_AS_U8,
casts::FN_TO_NUMERIC_CAST,
+ casts::FN_TO_NUMERIC_CAST_ANY,
casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
casts::PTR_AS_PTR,
casts::UNNECESSARY_CAST,
floating_point_arithmetic::IMPRECISE_FLOPS,
floating_point_arithmetic::SUBOPTIMAL_FLOPS,
format::USELESS_FORMAT,
+ format_args::FORMAT_IN_FORMAT_ARGS,
+ format_args::TO_STRING_IN_FORMAT_ARGS,
formatting::POSSIBLE_MISSING_COMMA,
formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING,
formatting::SUSPICIOUS_ELSE_FORMATTING,
map_unit_fn::RESULT_MAP_UNIT_FN,
match_on_vec_items::MATCH_ON_VEC_ITEMS,
match_result_ok::MATCH_RESULT_OK,
+ match_str_case_mismatch::MATCH_STR_CASE_MISMATCH,
matches::INFALLIBLE_DESTRUCTURING_MATCH,
matches::MATCH_AS_REF,
matches::MATCH_BOOL,
neg_multiply::NEG_MULTIPLY,
new_without_default::NEW_WITHOUT_DEFAULT,
no_effect::NO_EFFECT,
+ no_effect::NO_EFFECT_UNDERSCORE_BINDING,
no_effect::UNNECESSARY_OPERATION,
non_copy_const::BORROW_INTERIOR_MUTABLE_CONST,
non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST,
temporary_assignment::TEMPORARY_ASSIGNMENT,
to_digit_is_some::TO_DIGIT_IS_SOME,
to_string_in_display::TO_STRING_IN_DISPLAY,
+ trailing_empty_array::TRAILING_EMPTY_ARRAY,
trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS,
trait_bounds::TYPE_REPETITION_IN_BOUNDS,
transmute::CROSSPOINTER_TRANSMUTE,
transmute::TRANSMUTE_INT_TO_BOOL,
transmute::TRANSMUTE_INT_TO_CHAR,
transmute::TRANSMUTE_INT_TO_FLOAT,
+ transmute::TRANSMUTE_NUM_TO_BYTES,
transmute::TRANSMUTE_PTR_TO_PTR,
transmute::TRANSMUTE_PTR_TO_REF,
transmute::UNSOUND_COLLECTION_TRANSMUTE,
types::REDUNDANT_ALLOCATION,
types::TYPE_COMPLEXITY,
types::VEC_BOX,
+ undocumented_unsafe_blocks::UNDOCUMENTED_UNSAFE_BLOCKS,
undropped_manually_drops::UNDROPPED_MANUALLY_DROPS,
unicode::INVISIBLE_CHARACTERS,
unicode::NON_ASCII_LITERAL,
unicode::UNICODE_NOT_NFC,
+ uninit_vec::UNINIT_VEC,
unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD,
unit_types::LET_UNIT_VALUE,
unit_types::UNIT_ARG,
LintId::of(regex::TRIVIAL_REGEX),
LintId::of(strings::STRING_LIT_AS_BYTES),
LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
+ LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
LintId::of(transmute::USELESS_TRANSMUTE),
LintId::of(use_self::USE_SELF),
])
LintId::of(needless_continue::NEEDLESS_CONTINUE),
LintId::of(needless_for_each::NEEDLESS_FOR_EACH),
LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE),
+ LintId::of(no_effect::NO_EFFECT_UNDERSCORE_BINDING),
LintId::of(non_expressive_names::MANY_SINGLE_CHAR_NAMES),
LintId::of(non_expressive_names::SIMILAR_NAMES),
LintId::of(pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE),
store.register_group(true, "clippy::perf", Some("clippy_perf"), vec![
LintId::of(entry::MAP_ENTRY),
LintId::of(escape::BOXED_LOCAL),
+ LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
+ LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
LintId::of(large_const_arrays::LARGE_CONST_ARRAYS),
LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
LintId::of(loops::MANUAL_MEMCPY),
LintId::of(as_conversions::AS_CONVERSIONS),
LintId::of(asm_syntax::INLINE_ASM_X86_ATT_SYNTAX),
LintId::of(asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX),
+ LintId::of(casts::FN_TO_NUMERIC_CAST_ANY),
LintId::of(create_dir::CREATE_DIR),
LintId::of(dbg_macro::DBG_MACRO),
LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
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(unnecessary_self_imports::UNNECESSARY_SELF_IMPORTS),
LintId::of(unwrap_in_result::UNWRAP_IN_RESULT),
LintId::of(verbose_file_reads::VERBOSE_FILE_READS),
mod float_literal;
mod floating_point_arithmetic;
mod format;
+mod format_args;
mod formatting;
mod from_over_into;
mod from_str_radix_10;
mod map_unit_fn;
mod match_on_vec_items;
mod match_result_ok;
+mod match_str_case_mismatch;
mod matches;
mod mem_forget;
mod mem_replace;
mod temporary_assignment;
mod to_digit_is_some;
mod to_string_in_display;
+mod trailing_empty_array;
mod trait_bounds;
mod transmute;
mod transmuting_null;
mod try_err;
mod types;
+mod undocumented_unsafe_blocks;
mod undropped_manually_drops;
mod unicode;
+mod uninit_vec;
mod unit_return_expecting_ord;
mod unit_types;
mod unnamed_address;
store.register_late_pass(|| Box::new(blocks_in_if_conditions::BlocksInIfConditions));
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_return_expecting_ord::UnitReturnExpectingOrd));
store.register_late_pass(|| Box::new(strings::StringAdd));
store.register_late_pass(|| Box::new(implicit_return::ImplicitReturn));
store.register_late_pass(|| Box::new(bool_assert_comparison::BoolAssertComparison));
store.register_early_pass(move || Box::new(module_style::ModStyle));
store.register_late_pass(|| Box::new(unused_async::UnusedAsync));
- let disallowed_types = conf.disallowed_types.iter().cloned().collect::<FxHashSet<_>>();
- store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(&disallowed_types)));
+ let disallowed_types = conf.disallowed_types.clone();
+ store.register_late_pass(move || Box::new(disallowed_type::DisallowedType::new(disallowed_types.clone())));
let import_renames = conf.enforced_import_renames.clone();
store.register_late_pass(move || Box::new(missing_enforced_import_rename::ImportRename::new(import_renames.clone())));
let scripts = conf.allowed_scripts.clone();
store.register_late_pass(move || Box::new(if_then_panic::IfThenPanic));
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));
+
}
#[rustfmt::skip]
/// }
///
/// if let Ok(value) = iter.next() {
- /// vec.push_value)
+ /// vec.push(value)
/// }
/// ```
pub MATCH_RESULT_OK,
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::SymbolStr;
+use rustc_span::{sym, Span};
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `match` expressions modifying the case of a string with non-compliant arms
+ ///
+ /// ### Why is this bad?
+ /// The arm is unreachable, which is likely a mistake
+ ///
+ /// ### Example
+ /// ```rust
+ /// # let text = "Foo";
+ ///
+ /// match &*text.to_ascii_lowercase() {
+ /// "foo" => {},
+ /// "Bar" => {},
+ /// _ => {},
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// # let text = "Foo";
+ ///
+ /// match &*text.to_ascii_lowercase() {
+ /// "foo" => {},
+ /// "bar" => {},
+ /// _ => {},
+ /// }
+ /// ```
+ pub MATCH_STR_CASE_MISMATCH,
+ correctness,
+ "creation of a case altering match expression with non-compliant arms"
+}
+
+declare_lint_pass!(MatchStrCaseMismatch => [MATCH_STR_CASE_MISMATCH]);
+
+#[derive(Debug)]
+enum CaseMethod {
+ LowerCase,
+ AsciiLowerCase,
+ UpperCase,
+ AsciiUppercase,
+}
+
+impl LateLintPass<'_> for MatchStrCaseMismatch {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ if_chain! {
+ if !in_external_macro(cx.tcx.sess, expr.span);
+ if let ExprKind::Match(match_expr, arms, MatchSource::Normal) = expr.kind;
+ if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty(match_expr).kind();
+ if let ty::Str = ty.kind();
+ then {
+ let mut visitor = MatchExprVisitor {
+ cx,
+ case_method: None,
+ };
+
+ visitor.visit_expr(match_expr);
+
+ if let Some(case_method) = visitor.case_method {
+ if let Some((bad_case_span, bad_case_str)) = verify_case(&case_method, arms) {
+ lint(cx, &case_method, bad_case_span, &bad_case_str);
+ }
+ }
+ }
+ }
+ }
+}
+
+struct MatchExprVisitor<'a, 'tcx> {
+ cx: &'a LateContext<'tcx>,
+ case_method: Option<CaseMethod>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
+ type Map = Map<'tcx>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
+ match ex.kind {
+ ExprKind::MethodCall(segment, _, [receiver], _)
+ if self.case_altered(&*segment.ident.as_str(), receiver) => {},
+ _ => walk_expr(self, ex),
+ }
+ }
+}
+
+impl<'a, 'tcx> MatchExprVisitor<'a, 'tcx> {
+ fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> bool {
+ if let Some(case_method) = get_case_method(segment_ident) {
+ let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
+
+ if is_type_diagnostic_item(self.cx, ty, sym::String) || ty.kind() == &ty::Str {
+ self.case_method = Some(case_method);
+ return true;
+ }
+ }
+
+ false
+ }
+}
+
+fn get_case_method(segment_ident_str: &str) -> Option<CaseMethod> {
+ match segment_ident_str {
+ "to_lowercase" => Some(CaseMethod::LowerCase),
+ "to_ascii_lowercase" => Some(CaseMethod::AsciiLowerCase),
+ "to_uppercase" => Some(CaseMethod::UpperCase),
+ "to_ascii_uppercase" => Some(CaseMethod::AsciiUppercase),
+ _ => None,
+ }
+}
+
+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')) },
+ };
+
+ for arm in arms {
+ if_chain! {
+ if let PatKind::Lit(Expr {
+ kind: ExprKind::Lit(lit),
+ ..
+ }) = arm.pat.kind;
+ if let LitKind::Str(symbol, _) = lit.node;
+ let input = symbol.as_str();
+ if !case_check(&input);
+ then {
+ return Some((lit.span, input));
+ }
+ }
+ }
+
+ None
+}
+
+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::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()),
+ };
+
+ span_lint_and_sugg(
+ cx,
+ MATCH_STR_CASE_MISMATCH,
+ bad_case_span,
+ "this `match` arm has a differing case than its expression",
+ &*format!("consider changing the case of this arm to respect `{}`", method_str),
+ format!("\"{}\"", suggestion),
+ Applicability::MachineApplicable,
+ );
+}
'b: 'a,
I: Clone + Iterator<Item = &'a Pat<'b>>,
{
- if !has_only_ref_pats(pats.clone()) {
+ if !has_multiple_ref_pats(pats.clone()) {
return;
}
None
}
-fn has_only_ref_pats<'a, 'b, I>(pats: I) -> bool
+fn has_multiple_ref_pats<'a, 'b, I>(pats: I) -> bool
where
'b: 'a,
I: Iterator<Item = &'a Pat<'b>>,
{
- let mut at_least_one_is_true = false;
+ let mut ref_count = 0;
for opt in pats.map(|pat| match pat.kind {
PatKind::Ref(..) => Some(true), // &-patterns
PatKind::Wild => Some(false), // an "anything" wildcard is also fine
}) {
if let Some(inner) = opt {
if inner {
- at_least_one_is_true = true;
+ ref_count += 1;
}
} else {
return false;
}
}
- at_least_one_is_true
+ ref_count > 1
}
pub fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
}
declare_clippy_lint! {
- /// **What it does:** Checks for usages of `str::splitn(2, _)`
- ///
- /// **Why is this bad?** `split_once` is both clearer in intent and slightly more efficient.
- ///
- /// **Known problems:** None.
+ /// ### What it does
+ /// Checks for usages of `str::splitn(2, _)`
///
- /// **Example:**
+ /// ### Why is this bad?
+ /// `split_once` is both clearer in intent and slightly more efficient.
///
+ /// ### Example
/// ```rust,ignore
/// // Bad
/// let (key, value) = _.splitn(2, '=').next_tuple()?;
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_expr_path_def_path, match_def_path, paths};
+use clippy_utils::{is_expr_path_def_path, paths, ty::is_uninit_value_valid_for_ty};
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
use super::UNINIT_ASSUMED_INIT;
if let hir::ExprKind::Call(callee, args) = recv.kind;
if args.is_empty();
if is_expr_path_def_path(cx, callee, &paths::MEM_MAYBEUNINIT_UNINIT);
- if !is_maybe_uninit_ty_valid(cx, cx.typeck_results().expr_ty_adjusted(expr));
+ if !is_uninit_value_valid_for_ty(cx, cx.typeck_results().expr_ty_adjusted(expr));
then {
span_lint(
cx,
}
}
}
-
-fn is_maybe_uninit_ty_valid(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
- match ty.kind() {
- ty::Array(component, _) => is_maybe_uninit_ty_valid(cx, component),
- ty::Tuple(types) => types.types().all(|ty| is_maybe_uninit_ty_valid(cx, ty)),
- ty::Adt(adt, _) => match_def_path(cx, adt.did, &paths::MEM_MAYBEUNINIT),
- _ => false,
- }
-}
declare_clippy_lint! {
/// ### What it does
- /// it lints if an exported function, method, trait method with default impl,
+ /// It lints if an exported function, method, trait method with default impl,
/// or trait method impl is not `#[inline]`.
///
/// ### Why is this bad?
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
+ if in_external_macro(self.cx.sess(), ty.span) {
+ return;
+ }
+
if let hir::TyKind::Rptr(
_,
hir::MutTy {
use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
+use clippy_utils::is_lint_allowed;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::has_drop;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, Stmt, StmtKind, UnsafeSource};
+use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, PatKind, Stmt, StmtKind, UnsafeSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use std::ops::Deref;
/// Checks for statements which have no effect.
///
/// ### Why is this bad?
- /// Similar to dead code, these statements are actually
+ /// Unlike dead code, these statements are actually
/// executed. However, as they have no effect, all they do is make the code less
/// readable.
///
"statements with no effect"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for binding to underscore prefixed variable without side-effects.
+ ///
+ /// ### Why is this bad?
+ /// Unlike dead code, these bindings are actually
+ /// executed. However, as they have no effect and shouldn't be used further on, all they
+ /// do is make the code less readable.
+ ///
+ /// ### Known problems
+ /// Further usage of this variable is not checked, which can lead to false positives if it is
+ /// used later in the code.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let _i_serve_no_purpose = 1;
+ /// ```
+ pub NO_EFFECT_UNDERSCORE_BINDING,
+ pedantic,
+ "binding to `_` prefixed variable with no side-effect"
+}
+
declare_clippy_lint! {
/// ### What it does
/// Checks for expression statements that can be reduced to a
"outer expressions with no effect"
}
+declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION, NO_EFFECT_UNDERSCORE_BINDING]);
+
+impl<'tcx> LateLintPass<'tcx> for NoEffect {
+ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+ if check_no_effect(cx, stmt) {
+ return;
+ }
+ check_unnecessary_operation(cx, stmt);
+ }
+}
+
+fn check_no_effect(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> bool {
+ if let StmtKind::Semi(expr) = stmt.kind {
+ if has_no_effect(cx, expr) {
+ span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
+ return true;
+ }
+ } else if let StmtKind::Local(local) = stmt.kind {
+ if_chain! {
+ if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id);
+ if let Some(init) = local.init;
+ if !local.pat.span.from_expansion();
+ if has_no_effect(cx, init);
+ if let PatKind::Binding(_, _, ident, _) = local.pat.kind;
+ if ident.name.to_ident_string().starts_with('_');
+ then {
+ span_lint_hir(
+ cx,
+ NO_EFFECT_UNDERSCORE_BINDING,
+ init.hir_id,
+ stmt.span,
+ "binding to `_` prefixed variable with no side-effect"
+ );
+ return true;
+ }
+ }
+ }
+ false
+}
+
fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
if expr.span.from_expansion() {
return false;
}
}
-declare_lint_pass!(NoEffect => [NO_EFFECT, UNNECESSARY_OPERATION]);
-
-impl<'tcx> LateLintPass<'tcx> for NoEffect {
- fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
- if let StmtKind::Semi(expr) = stmt.kind {
- if has_no_effect(cx, expr) {
- span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
- } else if let Some(reduced) = reduce_expression(cx, expr) {
- for e in &reduced {
- if e.span.from_expansion() {
- return;
- }
- }
- if let ExprKind::Index(..) = &expr.kind {
- let snippet;
- if_chain! {
- if let Some(arr) = snippet_opt(cx, reduced[0].span);
- if let Some(func) = snippet_opt(cx, reduced[1].span);
- then {
- snippet = format!("assert!({}.len() > {});", &arr, &func);
- } else {
- return;
- }
- }
- span_lint_hir_and_then(
- cx,
- UNNECESSARY_OPERATION,
- expr.hir_id,
- stmt.span,
- "unnecessary operation",
- |diag| {
- diag.span_suggestion(
- stmt.span,
- "statement can be written as",
- snippet,
- Applicability::MaybeIncorrect,
- );
- },
- );
+fn check_unnecessary_operation(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+ if_chain! {
+ if let StmtKind::Semi(expr) = stmt.kind;
+ if let Some(reduced) = reduce_expression(cx, expr);
+ if !&reduced.iter().any(|e| e.span.from_expansion());
+ then {
+ if let ExprKind::Index(..) = &expr.kind {
+ let snippet;
+ if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) {
+ snippet = format!("assert!({}.len() > {});", &arr, &func);
} else {
- let mut snippet = String::new();
- for e in reduced {
- if let Some(snip) = snippet_opt(cx, e.span) {
- snippet.push_str(&snip);
- snippet.push(';');
- } else {
- return;
- }
+ return;
+ }
+ span_lint_hir_and_then(
+ cx,
+ UNNECESSARY_OPERATION,
+ expr.hir_id,
+ stmt.span,
+ "unnecessary operation",
+ |diag| {
+ diag.span_suggestion(
+ stmt.span,
+ "statement can be written as",
+ snippet,
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+ } else {
+ let mut snippet = String::new();
+ for e in reduced {
+ if let Some(snip) = snippet_opt(cx, e.span) {
+ snippet.push_str(&snip);
+ snippet.push(';');
+ } else {
+ return;
}
- span_lint_hir_and_then(
- cx,
- UNNECESSARY_OPERATION,
- expr.hir_id,
- stmt.span,
- "unnecessary operation",
- |diag| {
- diag.span_suggestion(
- stmt.span,
- "statement can be reduced to",
- snippet,
- Applicability::MachineApplicable,
- );
- },
- );
}
+ span_lint_hir_and_then(
+ cx,
+ UNNECESSARY_OPERATION,
+ expr.hir_id,
+ stmt.span,
+ "unnecessary operation",
+ |diag| {
+ diag.span_suggestion(
+ stmt.span,
+ "statement can be reduced to",
+ snippet,
+ Applicability::MachineApplicable,
+ );
+ },
+ );
}
}
}
/// unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
/// ```
///
+ /// ```ignore
/// // Good
/// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
/// ```
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{eq_expr_value, path_to_local_id};
+use clippy_utils::{eq_expr_value, path_to_local, path_to_local_id};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionNone, OptionSome};
+use rustc_hir::LangItem::{OptionNone, OptionSome, ResultOk};
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, PatKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
/// }
/// ```
///
+ /// ```ignore
+ /// if result.is_err() {
+ /// return result;
+ /// }
+ /// ```
+ ///
/// If it matches, it will suggest to use the question mark operator instead
- fn check_is_none_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ fn check_is_none_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
if let ExprKind::MethodCall(segment, _, args, _) = &cond.kind;
- if segment.ident.name == sym!(is_none);
- if Self::expression_returns_none(cx, then);
if let Some(subject) = args.get(0);
- if Self::is_option(cx, subject);
-
+ if (Self::option_check_and_early_return(cx, subject, then) && segment.ident.name == sym!(is_none)) ||
+ (Self::result_check_and_early_return(cx, subject, then) && segment.ident.name == sym!(is_err));
then {
let mut applicability = Applicability::MachineApplicable;
let receiver_str = &Sugg::hir_with_applicability(cx, subject, "..", &mut applicability);
}
}
- fn check_if_let_some_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ fn check_if_let_some_or_err_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>) {
if_chain! {
if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: Some(if_else) })
= higher::IfLet::hir(cx, expr);
- if Self::is_option(cx, let_expr);
-
if let PatKind::TupleStruct(ref path1, fields, None) = let_pat.kind;
- if is_lang_ctor(cx, path1, OptionSome);
+ if (Self::option_check_and_early_return(cx, let_expr, if_else) && is_lang_ctor(cx, path1, OptionSome)) ||
+ (Self::result_check_and_early_return(cx, let_expr, if_else) && is_lang_ctor(cx, path1, ResultOk));
+
if let PatKind::Binding(annot, bind_id, _, _) = fields[0].kind;
let by_ref = matches!(annot, BindingAnnotation::Ref | BindingAnnotation::RefMut);
-
if let ExprKind::Block(block, None) = if_then.kind;
if block.stmts.is_empty();
if let Some(trailing_expr) = &block.expr;
if path_to_local_id(trailing_expr, bind_id);
-
- if Self::expression_returns_none(cx, if_else);
then {
let mut applicability = Applicability::MachineApplicable;
let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
- let replacement = format!(
- "{}{}?",
- receiver_str,
- if by_ref { ".as_ref()" } else { "" },
- );
+ let replacement = format!("{}{}?", receiver_str, if by_ref { ".as_ref()" } else { "" },);
span_lint_and_sugg(
cx,
}
}
+ fn result_check_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>, nested_expr: &Expr<'_>) -> bool {
+ Self::is_result(cx, expr) && Self::expression_returns_unmodified_err(cx, nested_expr, expr)
+ }
+
+ fn option_check_and_early_return(cx: &LateContext<'_>, expr: &Expr<'_>, nested_expr: &Expr<'_>) -> bool {
+ Self::is_option(cx, expr) && Self::expression_returns_none(cx, nested_expr)
+ }
+
fn moves_by_default(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
let expr_ty = cx.typeck_results().expr_ty(expression);
is_type_diagnostic_item(cx, expr_ty, sym::Option)
}
+ fn is_result(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
+ let expr_ty = cx.typeck_results().expr_ty(expression);
+
+ is_type_diagnostic_item(cx, expr_ty, sym::Result)
+ }
+
fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool {
match expression.kind {
ExprKind::Block(block, _) => {
}
}
+ fn expression_returns_unmodified_err(
+ cx: &LateContext<'_>,
+ expression: &Expr<'_>,
+ origin_hir_id: &Expr<'_>,
+ ) -> bool {
+ match expression.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);
+ }
+
+ 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),
+ _ => false,
+ }
+ }
+
fn return_expression<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
// Check if last expression is a return statement. Then, return the expression
if_chain! {
impl<'tcx> LateLintPass<'tcx> for QuestionMark {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- Self::check_is_none_and_early_return_none(cx, expr);
- Self::check_if_let_some_and_early_return_none(cx, expr);
+ Self::check_is_none_or_err_and_early_return(cx, expr);
+ Self::check_if_let_some_or_err_and_early_return(cx, expr);
}
}
use crate::rustc_lint::LintContext;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_macro_callsite;
-use clippy_utils::{in_macro, sugg};
+use clippy_utils::sugg;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Block, ExprKind};
impl LateLintPass<'_> for SemicolonIfNothingReturned {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
if_chain! {
- if !in_macro(block.span);
+ if !block.span.from_expansion();
if let Some(expr) = block.expr;
let t_expr = cx.typeck_results().expr_ty(expr);
if t_expr.is_unit();
(SHADOW_SAME, msg)
},
Some(expr) if is_local_used(cx, expr, shadowed) => {
- let msg = format!(
- "`{}` is shadowed by `{}` which reuses the original value",
- snippet(cx, pat.span, "_"),
- snippet(cx, expr.span, "..")
- );
+ let msg = format!("`{}` is shadowed", snippet(cx, pat.span, "_"));
(SHADOW_REUSE, msg)
},
_ => {
Some(format!(
"{}{}{}",
snippet_with_applicability(cx, expr.span.with_hi(current_ident.span.lo()), "..", applicability),
- new_ident.to_string(),
+ new_ident,
snippet_with_applicability(cx, expr.span.with_lo(current_ident.span.hi()), "..", applicability),
))
})
--- /dev/null
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_hir::{HirId, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Const;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Displays a warning when a struct with a trailing zero-sized array is declared without a `repr` attribute.
+ ///
+ /// ### Why is this bad?
+ /// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjuction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed.
+ ///
+ /// ### Example
+ /// ```rust
+ /// struct RarelyUseful {
+ /// some_field: u32,
+ /// last: [u32; 0],
+ /// }
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust
+ /// #[repr(C)]
+ /// struct MoreOftenUseful {
+ /// some_field: usize,
+ /// last: [u32; 0],
+ /// }
+ /// ```
+ pub TRAILING_EMPTY_ARRAY,
+ nursery,
+ "struct with a trailing zero-sized array but without `#[repr(C)]` or another `repr` attribute"
+}
+declare_lint_pass!(TrailingEmptyArray => [TRAILING_EMPTY_ARRAY]);
+
+impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray {
+ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+ if is_struct_with_trailing_zero_sized_array(cx, item) && !has_repr_attr(cx, item.hir_id()) {
+ span_lint_and_help(
+ cx,
+ TRAILING_EMPTY_ARRAY,
+ item.span,
+ "trailing zero-sized array in a struct which is not marked with a `repr` attribute",
+ None,
+ &format!(
+ "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute",
+ cx.tcx.def_path_str(item.def_id.to_def_id())
+ ),
+ );
+ }
+ }
+}
+
+fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool {
+ if_chain! {
+ // First check if last field is an array
+ if let ItemKind::Struct(data, _) = &item.kind;
+ if let Some(last_field) = data.fields().last();
+ if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind;
+
+ // Then check if that that array zero-sized
+ let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
+ let length = Const::from_anon_const(cx.tcx, length_ldid);
+ let length = length.try_eval_usize(cx.tcx, cx.param_env);
+ if let Some(length) = length;
+ then {
+ length == 0
+ } else {
+ false
+ }
+ }
+}
+
+fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
+ cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::repr))
+}
mod transmute_int_to_bool;
mod transmute_int_to_char;
mod transmute_int_to_float;
+mod transmute_num_to_bytes;
mod transmute_ptr_to_ptr;
mod transmute_ptr_to_ref;
mod transmute_ref_to_ref;
"transmutes from a float to an integer"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for transmutes from a number to an array of `u8`
+ ///
+ /// ### Why this is bad?
+ /// Transmutes are dangerous and error-prone, whereas `to_ne_bytes`
+ /// is intuitive and safe.
+ ///
+ /// ### Example
+ /// ```rust
+ /// unsafe {
+ /// let x: [u8; 8] = std::mem::transmute(1i64);
+ /// }
+ ///
+ /// // should be
+ /// let x: [u8; 8] = 0i64.to_ne_bytes();
+ /// ```
+ pub TRANSMUTE_NUM_TO_BYTES,
+ complexity,
+ "transmutes from a number to an array of `u8`"
+}
+
declare_clippy_lint! {
/// ### What it does
/// Checks for transmutes from a pointer to a pointer, or
TRANSMUTE_INT_TO_BOOL,
TRANSMUTE_INT_TO_FLOAT,
TRANSMUTE_FLOAT_TO_INT,
+ TRANSMUTE_NUM_TO_BYTES,
UNSOUND_COLLECTION_TRANSMUTE,
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
]);
linted |= transmute_int_to_bool::check(cx, e, from_ty, to_ty, args);
linted |= transmute_int_to_float::check(cx, e, from_ty, to_ty, args, const_context);
linted |= transmute_float_to_int::check(cx, e, from_ty, to_ty, args, const_context);
+ linted |= transmute_num_to_bytes::check(cx, e, from_ty, to_ty, args, const_context);
linted |= unsound_collection_transmute::check(cx, e, from_ty, to_ty);
if !linted {
diag.span_suggestion(
e.span,
"consider using",
- format!("std::char::from_u32({}).unwrap()", arg.to_string()),
+ format!("std::char::from_u32({}).unwrap()", arg),
Applicability::Unspecified,
);
},
diag.span_suggestion(
e.span,
"consider using",
- format!("{}::from_bits({})", to_ty, arg.to_string()),
+ format!("{}::from_bits({})", to_ty, arg),
Applicability::Unspecified,
);
},
--- /dev/null
+use super::TRANSMUTE_NUM_TO_BYTES;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sugg;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty, UintTy};
+
+/// Checks for `transmute_int_to_float` lint.
+/// Returns `true` if it's triggered, otherwise returns `false`.
+pub(super) fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ e: &'tcx Expr<'_>,
+ from_ty: Ty<'tcx>,
+ to_ty: Ty<'tcx>,
+ args: &'tcx [Expr<'_>],
+ const_context: bool,
+) -> bool {
+ match (&from_ty.kind(), &to_ty.kind()) {
+ (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => {
+ if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) {
+ return false;
+ }
+ if matches!(from_ty.kind(), ty::Float(_)) && const_context {
+ // TODO: Remove when const_float_bits_conv is stabilized
+ // rust#72447
+ return false;
+ }
+
+ span_lint_and_then(
+ cx,
+ TRANSMUTE_NUM_TO_BYTES,
+ e.span,
+ &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
+ |diag| {
+ let arg = sugg::Sugg::hir(cx, &args[0], "..");
+ diag.span_suggestion(
+ e.span,
+ "consider using `to_ne_bytes()`",
+ format!("{}.to_ne_bytes()", arg),
+ Applicability::Unspecified,
+ );
+ },
+ );
+ true
+ },
+ _ => false,
+ }
+}
--- /dev/null
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::source::{indent_of, reindent_multiline, snippet};
+use clippy_utils::{in_macro, is_lint_allowed};
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, HirId, Local, UnsafeSource};
+use rustc_lexer::TokenKind;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::map::Map;
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{BytePos, Span};
+use std::borrow::Cow;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `unsafe` blocks without a `// Safety: ` comment
+ /// explaining why the unsafe operations performed inside
+ /// the block are safe.
+ ///
+ /// ### Why is this bad?
+ /// Undocumented unsafe blocks can make it difficult to
+ /// read and maintain code, as well as uncover unsoundness
+ /// and bugs.
+ ///
+ /// ### Example
+ /// ```rust
+ /// use std::ptr::NonNull;
+ /// let a = &mut 42;
+ ///
+ /// let ptr = unsafe { NonNull::new_unchecked(a) };
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// use std::ptr::NonNull;
+ /// let a = &mut 42;
+ ///
+ /// // Safety: references are guaranteed to be non-null.
+ /// let ptr = unsafe { NonNull::new_unchecked(a) };
+ /// ```
+ pub UNDOCUMENTED_UNSAFE_BLOCKS,
+ restriction,
+ "creating an unsafe block without explaining why it is safe"
+}
+
+impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS]);
+
+#[derive(Default)]
+pub struct UndocumentedUnsafeBlocks {
+ pub local_level: u32,
+ pub local_span: Option<Span>,
+ // The local was already checked for an overall safety comment
+ // There is no need to continue checking the blocks in the local
+ pub local_checked: bool,
+ // Since we can only check the blocks from expanded macros
+ // We have to omit the suggestion due to the actual definition
+ // Not being available to us
+ pub macro_expansion: bool,
+}
+
+impl LateLintPass<'_> for UndocumentedUnsafeBlocks {
+ fn check_block(&mut self, cx: &LateContext<'_>, block: &'_ Block<'_>) {
+ if_chain! {
+ if !self.local_checked;
+ if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id);
+ if !in_external_macro(cx.tcx.sess, block.span);
+ if let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules;
+ if let Some(enclosing_scope_hir_id) = cx.tcx.hir().get_enclosing_scope(block.hir_id);
+ if self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, block.span) == Some(false);
+ then {
+ let mut span = block.span;
+
+ if let Some(local_span) = self.local_span {
+ span = local_span;
+
+ let result = self.block_has_safety_comment(cx.tcx, enclosing_scope_hir_id, span);
+
+ if result.unwrap_or(true) {
+ self.local_checked = true;
+ return;
+ }
+ }
+
+ self.lint(cx, span);
+ }
+ }
+ }
+
+ fn check_local(&mut self, cx: &LateContext<'_>, local: &'_ Local<'_>) {
+ if_chain! {
+ if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, local.hir_id);
+ if !in_external_macro(cx.tcx.sess, local.span);
+ if let Some(init) = local.init;
+ then {
+ self.visit_expr(init);
+
+ if self.local_level > 0 {
+ self.local_span = Some(local.span);
+ }
+ }
+ }
+ }
+
+ fn check_block_post(&mut self, _: &LateContext<'_>, _: &'_ Block<'_>) {
+ self.local_level = self.local_level.saturating_sub(1);
+
+ if self.local_level == 0 {
+ self.local_checked = false;
+ self.local_span = None;
+ }
+ }
+}
+
+impl<'hir> Visitor<'hir> for UndocumentedUnsafeBlocks {
+ type Map = Map<'hir>;
+
+ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_expr(&mut self, ex: &'v Expr<'v>) {
+ match ex.kind {
+ ExprKind::Block(_, _) => self.local_level = self.local_level.saturating_add(1),
+ _ => walk_expr(self, ex),
+ }
+ }
+}
+
+impl UndocumentedUnsafeBlocks {
+ fn block_has_safety_comment(&mut self, tcx: TyCtxt<'_>, enclosing_hir_id: HirId, block_span: Span) -> Option<bool> {
+ let map = tcx.hir();
+ let source_map = tcx.sess.source_map();
+
+ let enclosing_scope_span = map.opt_span(enclosing_hir_id)?;
+
+ let between_span = if in_macro(block_span) {
+ self.macro_expansion = true;
+ enclosing_scope_span.with_hi(block_span.hi())
+ } else {
+ self.macro_expansion = false;
+ enclosing_scope_span.to(block_span)
+ };
+
+ 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 mut pos = 0;
+ let mut comment = false;
+
+ for token in rustc_lexer::tokenize(&src_str) {
+ match token.kind {
+ TokenKind::LineComment { doc_style: None }
+ | TokenKind::BlockComment {
+ doc_style: None,
+ terminated: true,
+ } => {
+ let comment_str = src_str[pos + 2..pos + token.len].to_ascii_uppercase();
+
+ if comment_str.contains("SAFETY:") {
+ comment = true;
+ }
+ },
+ // We need to add all whitespace to `pos` before checking the comment's line number
+ TokenKind::Whitespace => {},
+ _ => {
+ if comment {
+ // Get the line number of the "comment" (really wherever the trailing whitespace ended)
+ let comment_line_num = source_file
+ .lookup_file_pos_with_col_display(BytePos((lex_start + pos).try_into().unwrap()))
+ .0;
+ // Find the block/local's line number
+ let block_line_num = tcx.sess.source_map().lookup_char_pos(block_span.lo()).line;
+
+ // Check the comment is immediately followed by the block/local
+ if block_line_num == comment_line_num + 1 || block_line_num == comment_line_num {
+ return Some(true);
+ }
+
+ comment = false;
+ }
+ },
+ }
+
+ pos += token.len;
+ }
+
+ Some(false)
+ }
+
+ fn lint(&self, cx: &LateContext<'_>, mut span: Span) {
+ let source_map = cx.tcx.sess.source_map();
+
+ if source_map.is_multiline(span) {
+ span = source_map.span_until_char(span, '\n');
+ }
+
+ if self.macro_expansion {
+ span_lint_and_help(
+ cx,
+ UNDOCUMENTED_UNSAFE_BLOCKS,
+ span,
+ "unsafe block in macro expansion missing a safety comment",
+ None,
+ "consider adding a safety comment in the macro definition",
+ );
+ } else {
+ let block_indent = indent_of(cx, span);
+ let suggestion = format!("// Safety: ...\n{}", snippet(cx, span, ".."));
+
+ span_lint_and_sugg(
+ cx,
+ UNDOCUMENTED_UNSAFE_BLOCKS,
+ span,
+ "unsafe block missing a safety comment",
+ "consider adding a safety comment",
+ reindent_multiline(Cow::Borrowed(&suggestion), true, block_indent).to_string(),
+ Applicability::HasPlaceholders,
+ );
+ }
+ }
+}
--- /dev/null
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
+use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty};
+use clippy_utils::{is_lint_allowed, path_to_local_id, peel_hir_expr_while, SpanlessEq};
+use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, Span};
+
+// TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for `set_len()` call that creates `Vec` with uninitialized elements.
+ /// This is commonly caused by calling `set_len()` right after allocating or
+ /// reserving a buffer with `new()`, `default()`, `with_capacity()`, or `reserve()`.
+ ///
+ /// ### Why is this bad?
+ /// It creates a `Vec` with uninitialized data, which leads to
+ /// undefined behavior with most safe operations. Notably, uninitialized
+ /// `Vec<u8>` must not be used with generic `Read`.
+ ///
+ /// Moreover, calling `set_len()` on a `Vec` created with `new()` or `default()`
+ /// creates out-of-bound values that lead to heap memory corruption when used.
+ ///
+ /// ### Known Problems
+ /// This lint only checks directly adjacent statements.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ /// unsafe { vec.set_len(1000); }
+ /// reader.read(&mut vec); // undefined behavior!
+ /// ```
+ ///
+ /// ### How to fix?
+ /// 1. Use an initialized buffer:
+ /// ```rust,ignore
+ /// let mut vec: Vec<u8> = vec![0; 1000];
+ /// reader.read(&mut vec);
+ /// ```
+ /// 2. Wrap the content in `MaybeUninit`:
+ /// ```rust,ignore
+ /// let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
+ /// vec.set_len(1000); // `MaybeUninit` can be uninitialized
+ /// ```
+ /// 3. If you are on nightly, `Vec::spare_capacity_mut()` is available:
+ /// ```rust,ignore
+ /// let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ /// let remaining = vec.spare_capacity_mut(); // `&mut [MaybeUninit<u8>]`
+ /// // perform initialization with `remaining`
+ /// vec.set_len(...); // Safe to call `set_len()` on initialized part
+ /// ```
+ pub UNINIT_VEC,
+ correctness,
+ "Vec with uninitialized data"
+}
+
+declare_lint_pass!(UninitVec => [UNINIT_VEC]);
+
+// FIXME: update to a visitor-based implementation.
+// Threads: https://github.com/rust-lang/rust-clippy/pull/7682#discussion_r710998368
+impl<'tcx> LateLintPass<'tcx> for UninitVec {
+ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
+ if !in_external_macro(cx.tcx.sess, block.span) {
+ for w in block.stmts.windows(2) {
+ if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind {
+ handle_uninit_vec_pair(cx, &w[0], expr);
+ }
+ }
+
+ if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) {
+ handle_uninit_vec_pair(cx, stmt, expr);
+ }
+ }
+ }
+}
+
+fn handle_uninit_vec_pair(
+ cx: &LateContext<'tcx>,
+ maybe_init_or_reserve: &'tcx Stmt<'tcx>,
+ maybe_set_len: &'tcx Expr<'tcx>,
+) {
+ if_chain! {
+ if let Some(vec) = extract_init_or_reserve_target(cx, maybe_init_or_reserve);
+ if let Some((set_len_self, call_span)) = extract_set_len_self(cx, maybe_set_len);
+ if vec.location.eq_expr(cx, set_len_self);
+ if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind();
+ if let ty::Adt(_, substs) = vec_ty.kind();
+ // `#[allow(...)]` attribute can be set on enclosing unsafe block of `set_len()`
+ if !is_lint_allowed(cx, UNINIT_VEC, maybe_set_len.hir_id);
+ then {
+ if vec.has_capacity() {
+ // with_capacity / reserve -> set_len
+
+ // Check T of Vec<T>
+ if !is_uninit_value_valid_for_ty(cx, substs.type_at(0)) {
+ // FIXME: #7698, false positive of the internal lints
+ #[allow(clippy::collapsible_span_lint_calls)]
+ span_lint_and_then(
+ cx,
+ UNINIT_VEC,
+ vec![call_span, maybe_init_or_reserve.span],
+ "calling `set_len()` immediately after reserving a buffer creates uninitialized values",
+ |diag| {
+ diag.help("initialize the buffer or wrap the content in `MaybeUninit`");
+ },
+ );
+ }
+ } else {
+ // new / default -> set_len
+ span_lint(
+ cx,
+ UNINIT_VEC,
+ vec![call_span, maybe_init_or_reserve.span],
+ "calling `set_len()` on empty `Vec` creates out-of-bound values",
+ );
+ }
+ }
+ }
+}
+
+/// The target `Vec` that is initialized or reserved
+#[derive(Clone, Copy)]
+struct TargetVec<'tcx> {
+ location: VecLocation<'tcx>,
+ /// `None` if `reserve()`
+ init_kind: Option<VecInitKind>,
+}
+
+impl TargetVec<'_> {
+ pub fn has_capacity(self) -> bool {
+ !matches!(self.init_kind, Some(VecInitKind::New | VecInitKind::Default))
+ }
+}
+
+#[derive(Clone, Copy)]
+enum VecLocation<'tcx> {
+ Local(HirId),
+ Expr(&'tcx Expr<'tcx>),
+}
+
+impl<'tcx> VecLocation<'tcx> {
+ pub fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+ match self {
+ VecLocation::Local(hir_id) => path_to_local_id(expr, hir_id),
+ VecLocation::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr),
+ }
+ }
+}
+
+/// Finds the target location where the result of `Vec` initialization is stored
+/// or `self` expression for `Vec::reserve()`.
+fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) -> Option<TargetVec<'tcx>> {
+ match stmt.kind {
+ StmtKind::Local(local) => {
+ if_chain! {
+ if let Some(init_expr) = local.init;
+ if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind;
+ if let Some(init_kind) = get_vec_init_kind(cx, init_expr);
+ then {
+ return Some(TargetVec {
+ location: VecLocation::Local(hir_id),
+ init_kind: Some(init_kind),
+ })
+ }
+ }
+ },
+ StmtKind::Expr(expr) | StmtKind::Semi(expr) => match expr.kind {
+ ExprKind::Assign(lhs, rhs, _span) => {
+ if let Some(init_kind) = get_vec_init_kind(cx, rhs) {
+ return Some(TargetVec {
+ location: VecLocation::Expr(lhs),
+ init_kind: Some(init_kind),
+ });
+ }
+ },
+ ExprKind::MethodCall(path, _, [self_expr, _], _) if is_reserve(cx, path, self_expr) => {
+ return Some(TargetVec {
+ location: VecLocation::Expr(self_expr),
+ init_kind: None,
+ });
+ },
+ _ => (),
+ },
+ StmtKind::Item(_) => (),
+ }
+ None
+}
+
+fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool {
+ is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec)
+ && path.ident.name.as_str() == "reserve"
+}
+
+/// Returns self if the expression is `Vec::set_len()`
+fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> {
+ // peel unsafe blocks in `unsafe { vec.set_len() }`
+ let expr = peel_hir_expr_while(expr, |e| {
+ if let ExprKind::Block(block, _) = e.kind {
+ // Extract the first statement/expression
+ match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
+ (None, Some(expr)) => Some(expr),
+ (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr),
+ _ => None,
+ }
+ } else {
+ None
+ }
+ });
+ match expr.kind {
+ ExprKind::MethodCall(path, _, [self_expr, _], _) => {
+ let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs();
+ if is_type_diagnostic_item(cx, self_type, sym::Vec) && path.ident.name.as_str() == "set_len" {
+ Some((self_expr, expr.span))
+ } else {
+ None
+ }
+ },
+ _ => None,
+ }
+}
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegment, QPath};
let vec_name = Sugg::hir(cx, &args[0], "..").to_string();
let unstable = name == "sort_unstable_by";
+ if_chain! {
if let ExprKind::Path(QPath::Resolved(_, Path {
segments: [PathSegment { ident: left_name, .. }], ..
- })) = &left_expr.kind {
- if left_name == left_ident {
+ })) = &left_expr.kind;
+ if left_name == left_ident;
+ if cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
+ implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
+ });
+ then {
return Some(LintTrigger::Sort(SortDetection { vec_name, unstable }));
}
}
WithReason { path: String, reason: Option<String> },
}
+/// A single disallowed type, used by the `DISALLOWED_TYPE` lint.
+#[derive(Clone, Debug, Deserialize)]
+#[serde(untagged)]
+pub enum DisallowedType {
+ Simple(String),
+ WithReason { path: String, reason: Option<String> },
+}
+
/// Conf with parse errors
#[derive(Default)]
pub struct TryConf {
/// Lint: DISALLOWED_TYPE.
///
/// The list of disallowed types, written as fully qualified paths.
- (disallowed_types: Vec<String> = Vec::new()),
+ (disallowed_types: Vec<crate::utils::conf::DisallowedType> = Vec::new()),
/// Lint: UNREADABLE_LITERAL.
///
/// Should the fraction of a decimal be linted to include separators.
let segments: Vec<&str> = segments.iter().map(|sym| &**sym).collect();
if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id();
// Check if the matched type is a diagnostic item
- let diag_items = cx.tcx.diagnostic_items(ty_did.krate);
- if let Some(item_name) = diag_items.iter().find_map(|(k, v)| if *v == ty_did { Some(k) } else { None });
+ if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did);
then {
// TODO: check paths constants from external crates.
let cx_snippet = snippet(cx, context.span, "_");
if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
then {
// report the error around the `vec!` not inside `<std macros>:`
- let span = arg.span
- .ctxt()
- .outer_expn_data()
- .call_site
- .ctxt()
- .outer_expn_data()
- .call_site;
+ let span = arg.span.ctxt().outer_expn_data().call_site;
self.check_vec_macro(cx, &vec_args, Mutability::Not, span);
}
}
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::higher::{get_vec_init_kind, VecInitKind};
use clippy_utils::source::snippet;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{match_def_path, path_to_local, path_to_local_id, paths};
+use clippy_utils::{path_to_local, path_to_local_id};
use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Local, PatKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{symbol::sym, Span};
-use std::convert::TryInto;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
searcher: Option<VecPushSearcher>,
}
-#[derive(Clone, Copy)]
-enum VecInitKind {
- New,
- WithCapacity(u64),
-}
struct VecPushSearcher {
local_id: HirId,
init: VecInitKind,
fn display_err(&self, cx: &LateContext<'_>) {
match self.init {
_ if self.found == 0 => return,
- VecInitKind::WithCapacity(x) if x > self.found => return,
+ VecInitKind::WithLiteralCapacity(x) if x > self.found => return,
+ VecInitKind::WithExprCapacity(_) => return,
_ => (),
};
}
}
}
-
-fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<VecInitKind> {
- if let ExprKind::Call(func, args) = expr.kind {
- match func.kind {
- ExprKind::Path(QPath::TypeRelative(ty, name))
- if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) =>
- {
- if name.ident.name == sym::new {
- return Some(VecInitKind::New);
- } else if name.ident.name.as_str() == "with_capacity" {
- return args.get(0).and_then(|arg| {
- if_chain! {
- if let ExprKind::Lit(lit) = &arg.kind;
- if let LitKind::Int(num, _) = lit.node;
- then {
- Some(VecInitKind::WithCapacity(num.try_into().ok()?))
- } else {
- None
- }
- }
- });
- }
- }
- 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::New);
- }
- _ => (),
- }
- }
- None
-}
[package]
name = "clippy_utils"
-version = "0.1.57"
+version = "0.1.58"
edition = "2021"
publish = false
#![deny(clippy::missing_docs_in_private_items)]
-use crate::{is_expn_of, match_def_path, paths};
+use crate::ty::is_type_diagnostic_item;
+use crate::{is_expn_of, last_path_segment, match_def_path, paths};
use if_chain::if_chain;
use rustc_ast::ast::{self, LitKind};
use rustc_hir as hir;
-use rustc_hir::{Arm, Block, BorrowKind, Expr, ExprKind, LoopSource, MatchSource, Node, Pat, StmtKind, UnOp};
+use rustc_hir::{
+ Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp,
+};
use rustc_lint::LateContext;
-use rustc_span::{sym, ExpnKind, Span, Symbol};
+use rustc_span::{sym, symbol, ExpnKind, Span, Symbol};
/// The essential nodes of a desugared for loop as well as the entire span:
/// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`.
}
}
}
+
+ /// Returns a vector of `FormatArgsArg`.
+ pub fn args(&self) -> Option<Vec<FormatArgsArg<'tcx>>> {
+ if let Some(expr) = self.fmt_expr {
+ if_chain! {
+ if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
+ if let ExprKind::Array(exprs) = expr.kind;
+ then {
+ exprs.iter().map(|fmt| {
+ if_chain! {
+ // struct `core::fmt::rt::v1::Argument`
+ if let ExprKind::Struct(_, fields, _) = fmt.kind;
+ 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;
+ then {
+ let i = usize::try_from(position).unwrap();
+ Some(FormatArgsArg { value: self.value_args[i], arg: &self.args[i], fmt: Some(fmt) })
+ } else {
+ None
+ }
+ }
+ }).collect()
+ } else {
+ None
+ }
+ }
+ } else {
+ Some(
+ self.value_args
+ .iter()
+ .zip(self.args.iter())
+ .map(|(value, arg)| FormatArgsArg { value, arg, fmt: None })
+ .collect(),
+ )
+ }
+ }
+}
+
+/// Type representing a `FormatArgsExpn`'s format arguments
+pub struct FormatArgsArg<'tcx> {
+ /// An element of `value_args` according to `position`
+ pub value: &'tcx Expr<'tcx>,
+ /// An element of `args` according to `position`
+ pub arg: &'tcx Expr<'tcx>,
+ /// An element of `fmt_expn`
+ pub fmt: Option<&'tcx Expr<'tcx>>,
+}
+
+impl<'tcx> FormatArgsArg<'tcx> {
+ /// Returns true if any formatting parameters are used that would have an effect on strings,
+ /// like `{:+2}` instead of just `{}`.
+ pub fn has_string_formatting(&self) -> bool {
+ self.fmt.map_or(false, |fmt| {
+ // `!` because these conditions check that `self` is unformatted.
+ !if_chain! {
+ // struct `core::fmt::rt::v1::Argument`
+ if let ExprKind::Struct(_, fields, _) = fmt.kind;
+ if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
+ // struct `core::fmt::rt::v1::FormatSpec`
+ if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind;
+ let mut precision_found = false;
+ let mut width_found = false;
+ if subfields.iter().all(|field| {
+ match field.ident.name {
+ sym::precision => {
+ precision_found = true;
+ if let ExprKind::Path(ref precision_path) = field.expr.kind {
+ last_path_segment(precision_path).ident.name == sym::Implied
+ } else {
+ false
+ }
+ }
+ sym::width => {
+ width_found = true;
+ if let ExprKind::Path(ref width_qpath) = field.expr.kind {
+ last_path_segment(width_qpath).ident.name == sym::Implied
+ } else {
+ false
+ }
+ }
+ _ => true,
+ }
+ });
+ if precision_found && width_found;
+ then { true } else { false }
+ }
+ })
+ }
+
+ /// Returns true if the argument is formatted using `Display::fmt`.
+ pub fn is_display(&self) -> bool {
+ if_chain! {
+ if let ExprKind::Call(_, [_, format_field]) = self.arg.kind;
+ if let ExprKind::Path(QPath::Resolved(_, path)) = format_field.kind;
+ if let [.., t, _] = path.segments;
+ if t.ident.name == sym::Display;
+ then { true } else { false }
+ }
+ }
}
/// Checks if a `let` statement is from a `for` loop desugaring.
}
}
}
+
+/// A parsed `Vec` initialization expression
+#[derive(Clone, Copy)]
+pub enum VecInitKind {
+ /// `Vec::new()`
+ New,
+ /// `Vec::default()` or `Default::default()`
+ Default,
+ /// `Vec::with_capacity(123)`
+ WithLiteralCapacity(u64),
+ /// `Vec::with_capacity(slice.len())`
+ WithExprCapacity(HirId),
+}
+
+/// Checks if given expression is an initialization of `Vec` and returns its kind.
+pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<VecInitKind> {
+ if let ExprKind::Call(func, args) = expr.kind {
+ match func.kind {
+ ExprKind::Path(QPath::TypeRelative(ty, name))
+ if is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::Vec) =>
+ {
+ if name.ident.name == sym::new {
+ return Some(VecInitKind::New);
+ } else if name.ident.name == symbol::kw::Default {
+ return Some(VecInitKind::Default);
+ } else if name.ident.name.as_str() == "with_capacity" {
+ let arg = args.get(0)?;
+ if_chain! {
+ if let ExprKind::Lit(lit) = &arg.kind;
+ if let LitKind::Int(num, _) = lit.node;
+ then {
+ return Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?))
+ }
+ }
+ 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);
+ }
+ _ => (),
+ }
+ }
+ None
+}
use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::{HirIdMap, HirIdSet};
use rustc_hir::intravisit::{self, walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
use rustc_hir::{
- def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl,
- ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, Param, Pat,
- PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
+ def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, ForeignItem, GenericArgs,
+ HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node,
+ Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
+ UnOp,
};
use rustc_lint::{LateContext, Level, Lint, LintContext};
use rustc_middle::hir::exports::Export;
/// Returns `true` if this `span` was expanded by any macro.
#[must_use]
pub fn in_macro(span: Span) -> bool {
- if span.from_expansion() {
- !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
- } else {
- false
- }
+ span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
}
pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
}
let enclosing_body = cx.tcx.hir().local_def_id(cx.tcx.hir().enclosing_body_owner(e.hir_id));
if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) {
- value == v
- } else {
- false
+ return value == v;
}
+ false
}
/// Checks whether the given expression is a constant literal of the given value.
/// Returns the pre-expansion span if is this comes from an expansion of the
/// macro `name`.
-/// See also `is_direct_expn_of`.
+/// See also [`is_direct_expn_of`].
#[must_use]
pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
loop {
/// Returns the pre-expansion span if the span directly comes from an expansion
/// of the macro `name`.
-/// The difference with `is_expn_of` is that in
-/// ```rust,ignore
+/// The difference with [`is_expn_of`] is that in
+/// ```rust
+/// # macro_rules! foo { ($e:tt) => { $e } }; macro_rules! bar { ($e:expr) => { $e } }
/// foo!(bar!(42));
/// ```
/// `42` is considered expanded from `foo!` and `bar!` by `is_expn_of` but only
-/// `bar!` by
-/// `is_direct_expn_of`.
+/// from `bar!` by `is_direct_expn_of`.
#[must_use]
pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
if span.from_expansion() {
}
pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
- if_chain! {
- if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind;
- if let Res::SelfTy(..) = path.res;
- then {
- return true
+ if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind {
+ if let Res::SelfTy(..) = path.res {
+ return true;
}
}
false
}
pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
- if_chain! {
- if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
- if let Res::Def(_, def_id) = path.res;
- then {
- cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr)
- } else {
- false
+ if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
+ if let Res::Def(_, def_id) = path.res {
+ return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
}
}
+ false
}
-/// Checks whether item either has `test` attribute applied, or
-/// is a module with `test` in its name.
-pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
- if let Some(def_id) = tcx.hir().opt_local_def_id(item.hir_id()) {
- if tcx.has_attr(def_id.to_def_id(), sym::test) {
- return true;
+struct VisitConstTestStruct<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ names: Vec<Symbol>,
+ found: bool,
+}
+impl<'hir> ItemLikeVisitor<'hir> for VisitConstTestStruct<'hir> {
+ fn visit_item(&mut self, item: &Item<'_>) {
+ if let ItemKind::Const(ty, _body) = item.kind {
+ if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
+ // We could also check for the type name `test::TestDescAndFn`
+ // and the `#[rustc_test_marker]` attribute?
+ if let Res::Def(DefKind::Struct, _) = path.res {
+ let has_test_marker = self
+ .tcx
+ .hir()
+ .attrs(item.hir_id())
+ .iter()
+ .any(|a| a.has_name(sym::rustc_test_marker));
+ if has_test_marker && self.names.contains(&item.ident.name) {
+ self.found = true;
+ }
+ }
+ }
}
}
+ fn visit_trait_item(&mut self, _: &TraitItem<'_>) {}
+ fn visit_impl_item(&mut self, _: &ImplItem<'_>) {}
+ fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {}
+}
+
+/// Checks if the function containing the given `HirId` is a `#[test]` function
+///
+/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
+pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+ let names: Vec<_> = tcx
+ .hir()
+ .parent_iter(id)
+ // Since you can nest functions we need to collect all until we leave
+ // function scope
+ .filter_map(|(_id, node)| {
+ if let Node::Item(item) = node {
+ if let ItemKind::Fn(_, _, _) = item.kind {
+ return Some(item.ident.name);
+ }
+ }
+ None
+ })
+ .collect();
+ let parent_mod = tcx.parent_module(id);
+ let mut vis = VisitConstTestStruct {
+ tcx,
+ names,
+ found: false,
+ };
+ tcx.hir().visit_item_likes_in_module(parent_mod, &mut vis);
+ vis.found
+}
- matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().contains("test")
+/// Checks whether item either has `test` attribute appelied, or
+/// is a module with `test` in its name.
+///
+/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
+pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
+ is_in_test_function(tcx, item.hir_id())
+ || matches!(item.kind, ItemKind::Mod(..))
+ && item.ident.name.as_str().split('_').any(|a| a == "test" || a == "tests")
}
macro_rules! op_utils {
#[cfg(feature = "metadata-collector-lint")]
pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const ASSERT_EQ_MACRO: [&str; 3] = ["core", "macros", "assert_eq"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const ASSERT_MACRO: [&str; 4] = ["core", "macros", "builtin", "assert"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const ASSERT_NE_MACRO: [&str; 3] = ["core", "macros", "assert_ne"];
pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
#[cfg(feature = "internal-lints")]
pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const EPRINT_MACRO: [&str; 3] = ["std", "macros", "eprint"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const EPRINTLN_MACRO: [&str; 3] = ["std", "macros", "eprintln"];
pub const EXIT: [&str; 3] = ["std", "process", "exit"];
pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
pub const FILE: [&str; 3] = ["std", "fs", "File"];
pub const FILE_TYPE: [&str; 3] = ["std", "fs", "FileType"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const FORMAT_ARGS_MACRO: [&str; 4] = ["core", "macros", "builtin", "format_args"];
pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"];
pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const PRINT_MACRO: [&str; 3] = ["std", "macros", "print"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const PRINTLN_MACRO: [&str; 3] = ["std", "macros", "println"];
pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const WRITE_MACRO: [&str; 3] = ["core", "macros", "write"];
+#[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
+pub const WRITELN_MACRO: [&str; 3] = ["core", "macros", "writeln"];
_ => a == b,
}
}
+
+/// Checks if a given type looks safe to be uninitialized.
+pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
+ match ty.kind() {
+ ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component),
+ ty::Tuple(types) => types.types().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
+ ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did),
+ _ => false,
+ }
+}
# (experimental) Setup Clippy to work with IntelliJ-Rust
cargo dev setup intellij
```
+More about intellij command usage and reasons [here](../CONTRIBUTING.md#intellij-rust)
## lintcheck
`cargo lintcheck` will build and run clippy on a fixed set of crates and generate a log of the results.
[toolchain]
-channel = "nightly-2021-10-07"
+channel = "nightly-2021-10-21"
components = ["llvm-tools-preview", "rustc-dev", "rust-src"]
compiletest::run_tests(cfg);
}
+fn run_ui_test(cfg: &mut compiletest::Config) {
+ cfg.mode = TestMode::Ui;
+ cfg.src_base = Path::new("tests").join("ui_test");
+ let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
+ let rustcflags = cfg.target_rustcflags.get_or_insert_with(Default::default);
+ let len = rustcflags.len();
+ rustcflags.push_str(" --test");
+ compiletest::run_tests(cfg);
+ if let Some(ref mut flags) = &mut cfg.target_rustcflags {
+ flags.truncate(len);
+ }
+}
+
fn run_internal_tests(cfg: &mut compiletest::Config) {
// only run internal tests with the internal-tests feature
if !RUN_INTERNAL_TESTS {
prepare_env();
let mut config = default_config();
run_ui(&mut config);
+ run_ui_test(&mut config);
run_ui_toml(&mut config);
run_ui_cargo(&mut config);
run_internal_tests(&mut config);
--> $DIR/unnecessary_symbol_str.rs:14:5
|
LL | &*Ident::empty().as_str() == "clippy";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy`
error: unnecessary `Symbol` to string conversion
--> $DIR/unnecessary_symbol_str.rs:15:5
|
LL | "clippy" == Ident::empty().to_string();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name`
error: aborting due to 5 previous errors
+
"std::time::Instant",
"std::io::Read",
"std::primitive::usize",
- "bool"
+ "bool",
+ # can give path and reason with an inline table
+ { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
+ # can use an inline table but omit reason
+ { path = "std::net::TcpListener" },
]
static BAD: foo::atomic::AtomicPtr<()> = foo::atomic::AtomicPtr::new(std::ptr::null_mut());
+fn ip(_: std::net::Ipv4Addr) {}
+
+fn listener(_: std::net::TcpListener) {}
+
#[allow(clippy::diverging_sub_expression)]
fn main() {
let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
LL | struct GenArg<const U: usize>([u8; U]);
| ^^^^^
+error: `std::net::Ipv4Addr` is not allowed according to config
+ --> $DIR/conf_disallowed_type.rs:28:10
+ |
+LL | fn ip(_: std::net::Ipv4Addr) {}
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: no IPv4 allowed (from clippy.toml)
+
+error: `std::net::TcpListener` is not allowed according to config
+ --> $DIR/conf_disallowed_type.rs:30:16
+ |
+LL | fn listener(_: std::net::TcpListener) {}
+ | ^^^^^^^^^^^^^^^^^^^^^
+
error: `std::collections::HashMap` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:30:48
+ --> $DIR/conf_disallowed_type.rs:34:48
|
LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: `std::collections::HashMap` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:30:12
+ --> $DIR/conf_disallowed_type.rs:34:12
|
LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `std::time::Instant` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:31:13
+ --> $DIR/conf_disallowed_type.rs:35:13
|
LL | let _ = Sneaky::now();
| ^^^^^^
error: `std::sync::atomic::AtomicU32` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:32:13
+ --> $DIR/conf_disallowed_type.rs:36:13
|
LL | let _ = foo::atomic::AtomicU32::new(0);
| ^^^^^^^^^^^^^^^^^^^^^^
error: `std::sync::atomic::AtomicU32` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:33:17
+ --> $DIR/conf_disallowed_type.rs:37:17
|
LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `std::sync::atomic::AtomicU32` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:33:48
+ --> $DIR/conf_disallowed_type.rs:37:48
|
LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
| ^^^^^^^^^^^^^^^^^^^^^^
error: `syn::TypePath` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:34:43
+ --> $DIR/conf_disallowed_type.rs:38:43
|
LL | let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default();
| ^^^^^^^^^^^^^
error: `syn::Ident` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:35:13
+ --> $DIR/conf_disallowed_type.rs:39:13
|
LL | let _ = syn::Ident::new("", todo!());
| ^^^^^^^^^^
error: `usize` is not allowed according to config
- --> $DIR/conf_disallowed_type.rs:37:12
+ --> $DIR/conf_disallowed_type.rs:41:12
|
LL | let _: usize = 64_usize;
| ^^^^^
-error: aborting due to 19 previous errors
+error: aborting due to 21 previous errors
let x = 22;
};
}
+
+#[macro_export]
+macro_rules! mut_mut {
+ () => {
+ let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32;
+ };
+}
// run-rustfix
#![feature(stmt_expr_attributes)]
-#![allow(unused, clippy::no_effect)]
+#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
#![warn(clippy::deprecated_cfg_attr)]
// This doesn't get linted, see known problems
// run-rustfix
#![feature(stmt_expr_attributes)]
-#![allow(unused, clippy::no_effect)]
+#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
#![warn(clippy::deprecated_cfg_attr)]
// This doesn't get linted, see known problems
drive();
}
}
+
+// do not lint if any parent has `#[doc(hidden)]` attribute
+// see #7347
+#[doc(hidden)]
+pub mod __macro {
+ pub struct T;
+ impl T {
+ pub unsafe fn f() {}
+ }
+}
if g == NotStructuralEq::A {}
if let Some(NotPartialEq::A) = Some(f) {}
if Some(g) == Some(NotStructuralEq::A) {}
+
+ macro_rules! m1 {
+ (x) => {
+ "abc"
+ };
+ }
+ if "abc" == m1!(x) {
+ println!("OK");
+ }
}
if let NotStructuralEq::A = g {}
if let Some(NotPartialEq::A) = Some(f) {}
if let Some(NotStructuralEq::A) = Some(g) {}
+
+ macro_rules! m1 {
+ (x) => {
+ "abc"
+ };
+ }
+ if let m1!(x) = "abc" {
+ println!("OK");
+ }
}
LL | if let Some(NotStructuralEq::A) = Some(g) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)`
-error: aborting due to 10 previous errors
+error: this pattern matching can be expressed using equality
+ --> $DIR/equatable_if_let.rs:75:8
+ |
+LL | if let m1!(x) = "abc" {
+ | ^^^^^^^^^^^^^^^^^^ help: try: `"abc" == m1!(x)`
+
+error: aborting due to 11 previous errors
// run-rustfix
#![warn(clippy::expect_fun_call)]
+#![allow(clippy::to_string_in_format_args)]
/// Checks implementation of the `EXPECT_FUN_CALL` lint
// run-rustfix
#![warn(clippy::expect_fun_call)]
+#![allow(clippy::to_string_in_format_args)]
/// Checks implementation of the `EXPECT_FUN_CALL` lint
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:28:26
+ --> $DIR/expect_fun_call.rs:29:26
|
LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
= note: `-D clippy::expect-fun-call` implied by `-D warnings`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:31:26
+ --> $DIR/expect_fun_call.rs:32:26
|
LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:41:25
+ --> $DIR/expect_fun_call.rs:42:25
|
LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:44:25
+ --> $DIR/expect_fun_call.rs:45:25
|
LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:56:17
+ --> $DIR/expect_fun_call.rs:57:17
|
LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:77:21
+ --> $DIR/expect_fun_call.rs:78:21
|
LL | Some("foo").expect(&get_string());
| ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:78:21
+ --> $DIR/expect_fun_call.rs:79:21
|
LL | Some("foo").expect(get_string().as_ref());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:79:21
+ --> $DIR/expect_fun_call.rs:80:21
|
LL | Some("foo").expect(get_string().as_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:81:21
+ --> $DIR/expect_fun_call.rs:82:21
|
LL | Some("foo").expect(get_static_str());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:82:21
+ --> $DIR/expect_fun_call.rs:83:21
|
LL | Some("foo").expect(get_non_static_str(&0));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:86:16
+ --> $DIR/expect_fun_call.rs:87:16
|
LL | Some(true).expect(&format!("key {}, {}", 1, 2));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))`
error: use of `expect` followed by a function call
- --> $DIR/expect_fun_call.rs:92:17
+ --> $DIR/expect_fun_call.rs:93:17
|
LL | opt_ref.expect(&format!("{:?}", opt_ref));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))`
i: T,
j: U,
}
+
+mod issue6312 {
+ use std::sync::atomic::AtomicBool;
+ use std::sync::Arc;
+
+ // do not lint: type implements `Drop` but not all fields are `Copy`
+ #[derive(Clone, Default)]
+ pub struct ImplDropNotAllCopy {
+ name: String,
+ delay_data_sync: Arc<AtomicBool>,
+ }
+
+ impl Drop for ImplDropNotAllCopy {
+ fn drop(&mut self) {
+ self.close()
+ }
+ }
+
+ impl ImplDropNotAllCopy {
+ fn new(name: &str) -> Self {
+ let mut f = ImplDropNotAllCopy::default();
+ f.name = name.to_owned();
+ f
+ }
+ fn close(&self) {}
+ }
+
+ // lint: type implements `Drop` and all fields are `Copy`
+ #[derive(Clone, Default)]
+ pub struct ImplDropAllCopy {
+ name: usize,
+ delay_data_sync: bool,
+ }
+
+ impl Drop for ImplDropAllCopy {
+ fn drop(&mut self) {
+ self.close()
+ }
+ }
+
+ impl ImplDropAllCopy {
+ fn new(name: &str) -> Self {
+ let mut f = ImplDropAllCopy::default();
+ f.name = name.len();
+ f
+ }
+ fn close(&self) {}
+ }
+
+ // lint: type does not implement `Drop` though all fields are `Copy`
+ #[derive(Clone, Default)]
+ pub struct NoDropAllCopy {
+ name: usize,
+ delay_data_sync: bool,
+ }
+
+ impl NoDropAllCopy {
+ fn new(name: &str) -> Self {
+ let mut f = NoDropAllCopy::default();
+ f.name = name.len();
+ f
+ }
+ }
+}
LL | let mut a: WrapperMulti<i32, i64> = Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 9 previous errors
+error: field assignment outside of initializer for an instance created with Default::default()
+ --> $DIR/field_reassign_with_default.rs:229:13
+ |
+LL | f.name = name.len();
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `issue6312::ImplDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments
+ --> $DIR/field_reassign_with_default.rs:228:13
+ |
+LL | let mut f = ImplDropAllCopy::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: field assignment outside of initializer for an instance created with Default::default()
+ --> $DIR/field_reassign_with_default.rs:245:13
+ |
+LL | f.name = name.len();
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+note: consider initializing the variable with `issue6312::NoDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments
+ --> $DIR/field_reassign_with_default.rs:244:13
+ |
+LL | let mut f = NoDropAllCopy::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 11 previous errors
--- /dev/null
+#![warn(clippy::fn_to_numeric_cast_any)]
+#![allow(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)]
+
+fn foo() -> u8 {
+ 0
+}
+
+fn generic_foo<T>(x: T) -> T {
+ x
+}
+
+trait Trait {
+ fn static_method() -> u32 {
+ 2
+ }
+}
+
+struct Struct;
+
+impl Trait for Struct {}
+
+fn fn_pointer_to_integer() {
+ let _ = foo as i8;
+ let _ = foo as i16;
+ let _ = foo as i32;
+ let _ = foo as i64;
+ let _ = foo as i128;
+ let _ = foo as isize;
+
+ let _ = foo as u8;
+ let _ = foo as u16;
+ let _ = foo as u32;
+ let _ = foo as u64;
+ let _ = foo as u128;
+ let _ = foo as usize;
+}
+
+fn static_method_to_integer() {
+ let _ = Struct::static_method as usize;
+}
+
+fn fn_with_fn_arg(f: fn(i32) -> u32) -> usize {
+ f as usize
+}
+
+fn fn_with_generic_static_trait_method<T: Trait>() -> usize {
+ T::static_method as usize
+}
+
+fn closure_to_fn_to_integer() {
+ let clos = |x| x * 2_u32;
+
+ let _ = (clos as fn(u32) -> u32) as usize;
+}
+
+fn fn_to_raw_ptr() {
+ let _ = foo as *const ();
+}
+
+fn cast_fn_to_self() {
+ // Casting to the same function pointer type should be permitted.
+ let _ = foo as fn() -> u8;
+}
+
+fn cast_generic_to_concrete() {
+ // Casting to a more concrete function pointer type should be permitted.
+ let _ = generic_foo as fn(usize) -> usize;
+}
+
+fn cast_closure_to_fn() {
+ // Casting a closure to a function pointer should be permitted.
+ let id = |x| x;
+ let _ = id as fn(usize) -> usize;
+}
+
+fn main() {}
--- /dev/null
+error: casting function pointer `foo` to `i8`
+ --> $DIR/fn_to_numeric_cast_any.rs:23:13
+ |
+LL | let _ = foo as i8;
+ | ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i8`
+ |
+ = note: `-D clippy::fn-to-numeric-cast-any` implied by `-D warnings`
+
+error: casting function pointer `foo` to `i16`
+ --> $DIR/fn_to_numeric_cast_any.rs:24:13
+ |
+LL | let _ = foo as i16;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i16`
+
+error: casting function pointer `foo` to `i32`
+ --> $DIR/fn_to_numeric_cast_any.rs:25:13
+ |
+LL | let _ = foo as i32;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i32`
+
+error: casting function pointer `foo` to `i64`
+ --> $DIR/fn_to_numeric_cast_any.rs:26:13
+ |
+LL | let _ = foo as i64;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i64`
+
+error: casting function pointer `foo` to `i128`
+ --> $DIR/fn_to_numeric_cast_any.rs:27:13
+ |
+LL | let _ = foo as i128;
+ | ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as i128`
+
+error: casting function pointer `foo` to `isize`
+ --> $DIR/fn_to_numeric_cast_any.rs:28:13
+ |
+LL | let _ = foo as isize;
+ | ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as isize`
+
+error: casting function pointer `foo` to `u8`
+ --> $DIR/fn_to_numeric_cast_any.rs:30:13
+ |
+LL | let _ = foo as u8;
+ | ^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u8`
+
+error: casting function pointer `foo` to `u16`
+ --> $DIR/fn_to_numeric_cast_any.rs:31:13
+ |
+LL | let _ = foo as u16;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u16`
+
+error: casting function pointer `foo` to `u32`
+ --> $DIR/fn_to_numeric_cast_any.rs:32:13
+ |
+LL | let _ = foo as u32;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u32`
+
+error: casting function pointer `foo` to `u64`
+ --> $DIR/fn_to_numeric_cast_any.rs:33:13
+ |
+LL | let _ = foo as u64;
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u64`
+
+error: casting function pointer `foo` to `u128`
+ --> $DIR/fn_to_numeric_cast_any.rs:34:13
+ |
+LL | let _ = foo as u128;
+ | ^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as u128`
+
+error: casting function pointer `foo` to `usize`
+ --> $DIR/fn_to_numeric_cast_any.rs:35:13
+ |
+LL | let _ = foo as usize;
+ | ^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as usize`
+
+error: casting function pointer `Struct::static_method` to `usize`
+ --> $DIR/fn_to_numeric_cast_any.rs:39:13
+ |
+LL | let _ = Struct::static_method as usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `Struct::static_method() as usize`
+
+error: casting function pointer `f` to `usize`
+ --> $DIR/fn_to_numeric_cast_any.rs:43:5
+ |
+LL | f as usize
+ | ^^^^^^^^^^ help: did you mean to invoke the function?: `f() as usize`
+
+error: casting function pointer `T::static_method` to `usize`
+ --> $DIR/fn_to_numeric_cast_any.rs:47:5
+ |
+LL | T::static_method as usize
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `T::static_method() as usize`
+
+error: casting function pointer `(clos as fn(u32) -> u32)` to `usize`
+ --> $DIR/fn_to_numeric_cast_any.rs:53:13
+ |
+LL | let _ = (clos as fn(u32) -> u32) as usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `(clos as fn(u32) -> u32)() as usize`
+
+error: casting function pointer `foo` to `*const ()`
+ --> $DIR/fn_to_numeric_cast_any.rs:57:13
+ |
+LL | let _ = foo as *const ();
+ | ^^^^^^^^^^^^^^^^ help: did you mean to invoke the function?: `foo() as *const ()`
+
+error: aborting due to 17 previous errors
+
// run-rustfix
-#![allow(clippy::print_literal, clippy::redundant_clone)]
+#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
#![warn(clippy::useless_format)]
struct Foo(pub String);
// run-rustfix
-#![allow(clippy::print_literal, clippy::redundant_clone)]
+#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
#![warn(clippy::useless_format)]
struct Foo(pub String);
--- /dev/null
+// run-rustfix
+
+#![allow(unreachable_code)]
+#![allow(unused_macros)]
+#![allow(unused_variables)]
+#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::eq_op)]
+#![warn(clippy::to_string_in_format_args)]
+
+use std::io::{stdout, Write};
+use std::ops::Deref;
+use std::panic::Location;
+
+struct Somewhere;
+
+impl ToString for Somewhere {
+ fn to_string(&self) -> String {
+ String::from("somewhere")
+ }
+}
+
+struct X(u32);
+
+impl Deref for X {
+ type Target = u32;
+
+ fn deref(&self) -> &u32 {
+ &self.0
+ }
+}
+
+struct Y<'a>(&'a X);
+
+impl<'a> Deref for Y<'a> {
+ type Target = &'a X;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+struct Z(u32);
+
+impl Deref for Z {
+ type Target = u32;
+
+ fn deref(&self) -> &u32 {
+ &self.0
+ }
+}
+
+impl std::fmt::Display for Z {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "Z")
+ }
+}
+
+macro_rules! my_macro {
+ () => {
+ // here be dragons, do not enter (or lint)
+ println!("error: something failed at {}", Location::caller().to_string());
+ };
+}
+
+macro_rules! my_other_macro {
+ () => {
+ Location::caller().to_string()
+ };
+}
+
+fn main() {
+ let x = &X(1);
+ let x_ref = &x;
+
+ let _ = format!("error: something failed at {}", Location::caller());
+ let _ = write!(
+ stdout(),
+ "error: something failed at {}",
+ Location::caller()
+ );
+ let _ = writeln!(
+ stdout(),
+ "error: something failed at {}",
+ Location::caller()
+ );
+ print!("error: something failed at {}", Location::caller());
+ println!("error: something failed at {}", Location::caller());
+ eprint!("error: something failed at {}", Location::caller());
+ eprintln!("error: something failed at {}", Location::caller());
+ let _ = format_args!("error: something failed at {}", Location::caller());
+ assert!(true, "error: something failed at {}", Location::caller());
+ assert_eq!(0, 0, "error: something failed at {}", Location::caller());
+ assert_ne!(0, 0, "error: something failed at {}", Location::caller());
+ panic!("error: something failed at {}", Location::caller());
+ println!("{}", *X(1));
+ println!("{}", ***Y(&X(1)));
+ println!("{}", Z(1));
+ println!("{}", **x);
+ println!("{}", ***x_ref);
+
+ println!("error: something failed at {}", Somewhere.to_string());
+ println!("{} and again {0}", x.to_string());
+ my_macro!();
+ println!("error: something failed at {}", my_other_macro!());
+}
--- /dev/null
+// run-rustfix
+
+#![allow(unreachable_code)]
+#![allow(unused_macros)]
+#![allow(unused_variables)]
+#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::eq_op)]
+#![warn(clippy::to_string_in_format_args)]
+
+use std::io::{stdout, Write};
+use std::ops::Deref;
+use std::panic::Location;
+
+struct Somewhere;
+
+impl ToString for Somewhere {
+ fn to_string(&self) -> String {
+ String::from("somewhere")
+ }
+}
+
+struct X(u32);
+
+impl Deref for X {
+ type Target = u32;
+
+ fn deref(&self) -> &u32 {
+ &self.0
+ }
+}
+
+struct Y<'a>(&'a X);
+
+impl<'a> Deref for Y<'a> {
+ type Target = &'a X;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+struct Z(u32);
+
+impl Deref for Z {
+ type Target = u32;
+
+ fn deref(&self) -> &u32 {
+ &self.0
+ }
+}
+
+impl std::fmt::Display for Z {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "Z")
+ }
+}
+
+macro_rules! my_macro {
+ () => {
+ // here be dragons, do not enter (or lint)
+ println!("error: something failed at {}", Location::caller().to_string());
+ };
+}
+
+macro_rules! my_other_macro {
+ () => {
+ Location::caller().to_string()
+ };
+}
+
+fn main() {
+ let x = &X(1);
+ let x_ref = &x;
+
+ let _ = format!("error: something failed at {}", Location::caller().to_string());
+ let _ = write!(
+ stdout(),
+ "error: something failed at {}",
+ Location::caller().to_string()
+ );
+ let _ = writeln!(
+ stdout(),
+ "error: something failed at {}",
+ Location::caller().to_string()
+ );
+ print!("error: something failed at {}", Location::caller().to_string());
+ println!("error: something failed at {}", Location::caller().to_string());
+ eprint!("error: something failed at {}", Location::caller().to_string());
+ eprintln!("error: something failed at {}", Location::caller().to_string());
+ let _ = format_args!("error: something failed at {}", Location::caller().to_string());
+ assert!(true, "error: something failed at {}", Location::caller().to_string());
+ assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string());
+ assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string());
+ panic!("error: something failed at {}", Location::caller().to_string());
+ println!("{}", X(1).to_string());
+ println!("{}", Y(&X(1)).to_string());
+ println!("{}", Z(1).to_string());
+ println!("{}", x.to_string());
+ println!("{}", x_ref.to_string());
+
+ println!("error: something failed at {}", Somewhere.to_string());
+ println!("{} and again {0}", x.to_string());
+ my_macro!();
+ println!("error: something failed at {}", my_other_macro!());
+}
--- /dev/null
+error: `to_string` applied to a type that implements `Display` in `format!` args
+ --> $DIR/format_args.rs:75: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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+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
+ |
+LL | println!("{}", x_ref.to_string());
+ | ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref`
+
+error: aborting due to 17 previous errors
+
--- /dev/null
+#![allow(clippy::assertions_on_constants)]
+#![allow(clippy::eq_op)]
+#![warn(clippy::format_in_format_args)]
+#![warn(clippy::to_string_in_format_args)]
+
+use std::io::{stdout, Error, ErrorKind, Write};
+use std::ops::Deref;
+use std::panic::Location;
+
+macro_rules! my_macro {
+ () => {
+ // here be dragons, do not enter (or lint)
+ println!("error: {}", format!("something failed at {}", Location::caller()));
+ };
+}
+
+macro_rules! my_other_macro {
+ () => {
+ format!("something failed at {}", Location::caller())
+ };
+}
+
+fn main() {
+ let error = Error::new(ErrorKind::Other, "bad thing");
+ let x = 'x';
+
+ println!("error: {}", format!("something failed at {}", Location::caller()));
+ println!("{}: {}", error, format!("something failed at {}", Location::caller()));
+ println!("{:?}: {}", error, format!("something failed at {}", Location::caller()));
+ println!("{{}}: {}", format!("something failed at {}", Location::caller()));
+ println!(r#"error: "{}""#, format!("something failed at {}", Location::caller()));
+ println!("error: {}", format!(r#"something failed at "{}""#, Location::caller()));
+ println!("error: {}", format!("something failed at {} {0}", Location::caller()));
+ let _ = format!("error: {}", format!("something failed at {}", Location::caller()));
+ let _ = write!(
+ stdout(),
+ "error: {}",
+ format!("something failed at {}", Location::caller())
+ );
+ let _ = writeln!(
+ stdout(),
+ "error: {}",
+ format!("something failed at {}", Location::caller())
+ );
+ print!("error: {}", format!("something failed at {}", Location::caller()));
+ eprint!("error: {}", format!("something failed at {}", Location::caller()));
+ eprintln!("error: {}", format!("something failed at {}", Location::caller()));
+ let _ = format_args!("error: {}", format!("something failed at {}", Location::caller()));
+ assert!(true, "error: {}", format!("something failed at {}", Location::caller()));
+ assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+ assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+ panic!("error: {}", format!("something failed at {}", Location::caller()));
+
+ 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()));
+ println!("{} and again {0}", format!("hi {}", x));
+ my_macro!();
+ println!("error: {}", my_other_macro!());
+}
--- /dev/null
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:27:5
+ |
+LL | println!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::format-in-format-args` implied by `-D warnings`
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:28:5
+ |
+LL | println!("{}: {}", error, format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:29:5
+ |
+LL | println!("{:?}: {}", error, format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:30:5
+ |
+LL | println!("{{}}: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:31:5
+ |
+LL | println!(r#"error: "{}""#, format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:32:5
+ |
+LL | println!("error: {}", format!(r#"something failed at "{}""#, Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `println!` args
+ --> $DIR/format_args_unfixable.rs:33:5
+ |
+LL | println!("error: {}", format!("something failed at {} {0}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `println!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `format!` args
+ --> $DIR/format_args_unfixable.rs:34:13
+ |
+LL | let _ = format!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `format!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `write!` args
+ --> $DIR/format_args_unfixable.rs:35:13
+ |
+LL | let _ = write!(
+ | _____________^
+LL | | stdout(),
+LL | | "error: {}",
+LL | | format!("something failed at {}", Location::caller())
+LL | | );
+ | |_____^
+ |
+ = help: combine the `format!(..)` arguments with the outer `write!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `writeln!` args
+ --> $DIR/format_args_unfixable.rs:40:13
+ |
+LL | let _ = writeln!(
+ | _____________^
+LL | | stdout(),
+LL | | "error: {}",
+LL | | format!("something failed at {}", Location::caller())
+LL | | );
+ | |_____^
+ |
+ = help: combine the `format!(..)` arguments with the outer `writeln!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `print!` args
+ --> $DIR/format_args_unfixable.rs:45:5
+ |
+LL | print!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `print!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `eprint!` args
+ --> $DIR/format_args_unfixable.rs:46:5
+ |
+LL | eprint!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `eprint!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `eprintln!` args
+ --> $DIR/format_args_unfixable.rs:47:5
+ |
+LL | eprintln!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `eprintln!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `format_args!` args
+ --> $DIR/format_args_unfixable.rs:48:13
+ |
+LL | let _ = format_args!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `format_args!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `assert!` args
+ --> $DIR/format_args_unfixable.rs:49:5
+ |
+LL | assert!(true, "error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `assert!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `assert_eq!` args
+ --> $DIR/format_args_unfixable.rs:50:5
+ |
+LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `assert_eq!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `assert_ne!` args
+ --> $DIR/format_args_unfixable.rs:51:5
+ |
+LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `assert_ne!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: `format!` in `panic!` args
+ --> $DIR/format_args_unfixable.rs:52:5
+ |
+LL | panic!("error: {}", format!("something failed at {}", Location::caller()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: combine the `format!(..)` arguments with the outer `panic!(..)` call
+ = help: or consider changing `format!` to `format_args!`
+
+error: aborting due to 18 previous errors
+
if i_64 != 0 {
i_64 -= 1;
}
+
+ // issue #7831
+ // No Lint
+ if u_32 > 0 {
+ u_32 -= 1;
+ } else {
+ println!("side effect");
+ }
}
if i_64 != 0 {
i_64 -= 1;
}
+
+ // issue #7831
+ // No Lint
+ if u_32 > 0 {
+ u_32 -= 1;
+ } else {
+ println!("side effect");
+ }
}
LL | | };
| |_________^ help: try this: `matches!(&val, &Some(ref _a))`
-error: you don't need to add `&` to both the expression and the patterns
- --> $DIR/match_expr_like_matches_macro.rs:166:20
- |
-LL | let _res = match &val {
- | ____________________^
-LL | | &Some(ref _a) => true,
-LL | | _ => false,
-LL | | };
- | |_________^
- |
- = note: `-D clippy::match-ref-pats` implied by `-D warnings`
-help: try
- |
-LL ~ let _res = match val {
-LL ~ Some(ref _a) => true,
- |
-
error: match expression looks like `matches!` macro
--> $DIR/match_expr_like_matches_macro.rs:178:20
|
LL | | };
| |_________^ help: try this: `matches!(&val, &Some(ref _a))`
-error: you don't need to add `&` to both the expression and the patterns
- --> $DIR/match_expr_like_matches_macro.rs:178:20
- |
-LL | let _res = match &val {
- | ____________________^
-LL | | &Some(ref _a) => true,
-LL | | _ => false,
-LL | | };
- | |_________^
- |
-help: try
- |
-LL ~ let _res = match val {
-LL ~ Some(ref _a) => true,
- |
-
-error: aborting due to 14 previous errors
+error: aborting due to 12 previous errors
const FOO: u64 = 2;
match 42 {
- 0..=10 => println!("0 ... 10"),
- 0..=11 => println!("0 ... 11"),
+ 0..=10 => println!("0..=10"),
+ 0..=11 => println!("0..=11"),
_ => (),
}
match 42 {
- 0..=5 => println!("0 ... 5"),
- 6..=7 => println!("6 ... 7"),
- FOO..=11 => println!("0 ... 11"),
+ 0..=5 => println!("0..=5"),
+ 6..=7 => println!("6..=7"),
+ FOO..=11 => println!("FOO..=11"),
_ => (),
}
match 42 {
2 => println!("2"),
- 0..=5 => println!("0 ... 5"),
+ 0..=5 => println!("0..=5"),
_ => (),
}
match 42 {
2 => println!("2"),
- 0..=2 => println!("0 ... 2"),
+ 0..=2 => println!("0..=2"),
_ => (),
}
match 42 {
- 0..=10 => println!("0 ... 10"),
- 11..=50 => println!("11 ... 50"),
+ 0..=10 => println!("0..=10"),
+ 11..=50 => println!("11..=50"),
_ => (),
}
match 42 {
2 => println!("2"),
- 0..2 => println!("0 .. 2"),
+ 0..2 => println!("0..2"),
_ => (),
}
match 42 {
- 0..10 => println!("0 .. 10"),
- 10..50 => println!("10 .. 50"),
+ 0..10 => println!("0..10"),
+ 10..50 => println!("10..50"),
_ => (),
}
match 42 {
- 0..11 => println!("0 .. 11"),
- 0..=11 => println!("0 ... 11"),
+ 0..11 => println!("0..11"),
+ 0..=11 => println!("0..=11"),
_ => (),
}
match 42 {
- 5..7 => println!("5 .. 7"),
- 0..10 => println!("0 .. 10"),
+ 5..7 => println!("5..7"),
+ 0..10 => println!("0..10"),
_ => (),
}
match 42 {
- 5..10 => println!("5 .. 10"),
- 0..=10 => println!("0 ... 10"),
+ 5..10 => println!("5..10"),
+ 0..=10 => println!("0..=10"),
_ => (),
}
match 42 {
- 0..14 => println!("0 .. 14"),
- 5..10 => println!("5 .. 10"),
+ 0..14 => println!("0..14"),
+ 5..10 => println!("5..10"),
_ => (),
}
match 42 {
- 5..14 => println!("5 .. 14"),
- 0..=10 => println!("0 ... 10"),
+ 5..14 => println!("5..14"),
+ 0..=10 => println!("0..=10"),
_ => (),
}
match 42 {
- 0..7 => println!("0 .. 7"),
- 0..=10 => println!("0 ... 10"),
+ 0..7 => println!("0..7"),
+ 0..=10 => println!("0..=10"),
_ => (),
}
- /*
- // FIXME(JohnTitor): uncomment this once rustfmt knows half-open patterns
match 42 {
- 0.. => println!("0 .. 42"),
- 3.. => println!("3 .. 42"),
+ 3.. => println!("3.."),
+ 0.. => println!("0.."),
_ => (),
}
match 42 {
- ..=23 => println!("0 ... 23"),
- ..26 => println!("0 .. 26"),
+ ..=23 => println!("..=23"),
+ ..26 => println!("..26"),
_ => (),
}
- */
if let None = Some(42) {
// nothing
error: some ranges overlap
--> $DIR/match_overlapping_arm.rs:13:9
|
-LL | 0..=10 => println!("0 ... 10"),
+LL | 0..=10 => println!("0..=10"),
| ^^^^^^
|
= note: `-D clippy::match-overlapping-arm` implied by `-D warnings`
note: overlaps with this
--> $DIR/match_overlapping_arm.rs:14:9
|
-LL | 0..=11 => println!("0 ... 11"),
+LL | 0..=11 => println!("0..=11"),
| ^^^^^^
error: some ranges overlap
--> $DIR/match_overlapping_arm.rs:19:9
|
-LL | 0..=5 => println!("0 ... 5"),
+LL | 0..=5 => println!("0..=5"),
| ^^^^^
|
note: overlaps with this
--> $DIR/match_overlapping_arm.rs:21:9
|
-LL | FOO..=11 => println!("0 ... 11"),
+LL | FOO..=11 => println!("FOO..=11"),
| ^^^^^^^^
error: some ranges overlap
--> $DIR/match_overlapping_arm.rs:56:9
|
-LL | 0..11 => println!("0 .. 11"),
+LL | 0..11 => println!("0..11"),
| ^^^^^
|
note: overlaps with this
--> $DIR/match_overlapping_arm.rs:57:9
|
-LL | 0..=11 => println!("0 ... 11"),
+LL | 0..=11 => println!("0..=11"),
| ^^^^^^
error: some ranges overlap
--> $DIR/match_overlapping_arm.rs:81:9
|
-LL | 0..=10 => println!("0 ... 10"),
+LL | 0..=10 => println!("0..=10"),
| ^^^^^^
|
note: overlaps with this
--> $DIR/match_overlapping_arm.rs:80:9
|
-LL | 5..14 => println!("5 .. 14"),
+LL | 5..14 => println!("5..14"),
| ^^^^^
error: some ranges overlap
--> $DIR/match_overlapping_arm.rs:86:9
|
-LL | 0..7 => println!("0 .. 7"),
+LL | 0..7 => println!("0..7"),
| ^^^^
|
note: overlaps with this
--> $DIR/match_overlapping_arm.rs:87:9
|
-LL | 0..=10 => println!("0 ... 10"),
+LL | 0..=10 => println!("0..=10"),
| ^^^^^^
-error: aborting due to 5 previous errors
+error: some ranges overlap
+ --> $DIR/match_overlapping_arm.rs:98:9
+ |
+LL | ..=23 => println!("..=23"),
+ | ^^^^^
+ |
+note: overlaps with this
+ --> $DIR/match_overlapping_arm.rs:99:9
+ |
+LL | ..26 => println!("..26"),
+ | ^^^^
+
+error: aborting due to 6 previous errors
}
}
+mod issue_7740 {
+ macro_rules! foobar_variant(
+ ($idx:expr) => (FooBar::get($idx).unwrap())
+ );
+
+ enum FooBar {
+ Foo,
+ Bar,
+ FooBar,
+ BarFoo,
+ }
+
+ impl FooBar {
+ fn get(idx: u8) -> Option<&'static Self> {
+ match idx {
+ 0 => Some(&FooBar::Foo),
+ 1 => Some(&FooBar::Bar),
+ 2 => Some(&FooBar::FooBar),
+ 3 => Some(&FooBar::BarFoo),
+ _ => None,
+ }
+ }
+ }
+
+ fn issue_7740() {
+ // Issue #7740
+ match foobar_variant!(0) {
+ &FooBar::Foo => println!("Foo"),
+ &FooBar::Bar => println!("Bar"),
+ &FooBar::FooBar => println!("FooBar"),
+ _ => println!("Wild"),
+ }
+
+ // This shouldn't trigger
+ if let &FooBar::BarFoo = foobar_variant!(3) {
+ println!("BarFoo");
+ } else {
+ println!("Wild");
+ }
+ }
+}
+
fn main() {}
LL ~ None => println!("none"),
|
-error: you don't need to add `&` to all patterns
- --> $DIR/match_ref_pats.rs:18:5
- |
-LL | / match tup {
-LL | | &(v, 1) => println!("{}", v),
-LL | | _ => println!("none"),
-LL | | }
- | |_____^
- |
-help: instead of prefixing all patterns with `&`, you can dereference the expression
- |
-LL ~ match *tup {
-LL ~ (v, 1) => println!("{}", v),
- |
-
error: you don't need to add `&` to both the expression and the patterns
--> $DIR/match_ref_pats.rs:24:5
|
|
= note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
-error: you don't need to add `&` to all patterns
- --> $DIR/match_ref_pats.rs:36:5
- |
-LL | / if let &None = a {
-LL | | println!("none");
-LL | | }
- | |_____^
- |
-help: instead of prefixing all patterns with `&`, you can dereference the expression
- |
-LL | if let None = *a {
- | ~~~~ ~~
-
error: redundant pattern matching, consider using `is_none()`
--> $DIR/match_ref_pats.rs:41:12
|
LL | if let &None = &b {
| -------^^^^^----- help: try this: `if b.is_none()`
-error: you don't need to add `&` to both the expression and the patterns
- --> $DIR/match_ref_pats.rs:41:5
- |
-LL | / if let &None = &b {
-LL | | println!("none");
-LL | | }
- | |_____^
- |
-help: try
- |
-LL | if let None = b {
- | ~~~~ ~
-
error: you don't need to add `&` to all patterns
- --> $DIR/match_ref_pats.rs:68:9
+ --> $DIR/match_ref_pats.rs:101:9
|
-LL | / match foo_variant!(0) {
-LL | | &Foo::A => println!("A"),
+LL | / match foobar_variant!(0) {
+LL | | &FooBar::Foo => println!("Foo"),
+LL | | &FooBar::Bar => println!("Bar"),
+LL | | &FooBar::FooBar => println!("FooBar"),
LL | | _ => println!("Wild"),
LL | | }
| |_________^
|
help: instead of prefixing all patterns with `&`, you can dereference the expression
|
-LL ~ match *foo_variant!(0) {
-LL ~ Foo::A => println!("A"),
+LL ~ match *foobar_variant!(0) {
+LL ~ FooBar::Foo => println!("Foo"),
+LL ~ FooBar::Bar => println!("Bar"),
+LL ~ FooBar::FooBar => println!("FooBar"),
|
-error: aborting due to 8 previous errors
+error: aborting due to 5 previous errors
--- /dev/null
+#![warn(clippy::match_str_case_mismatch)]
+
+// Valid
+
+fn as_str_match() {
+ let var = "BAR";
+
+ match var.to_ascii_lowercase().as_str() {
+ "foo" => {},
+ "bar" => {},
+ _ => {},
+ }
+}
+
+fn addrof_unary_match() {
+ let var = "BAR";
+
+ match &*var.to_ascii_lowercase() {
+ "foo" => {},
+ "bar" => {},
+ _ => {},
+ }
+}
+
+fn alternating_chain() {
+ let var = "BAR";
+
+ match &*var
+ .to_ascii_lowercase()
+ .to_uppercase()
+ .to_lowercase()
+ .to_ascii_uppercase()
+ {
+ "FOO" => {},
+ "BAR" => {},
+ _ => {},
+ }
+}
+
+fn unrelated_method() {
+ struct Item {
+ a: String,
+ }
+
+ impl Item {
+ #[allow(clippy::wrong_self_convention)]
+ fn to_lowercase(self) -> String {
+ self.a
+ }
+ }
+
+ let item = Item { a: String::from("BAR") };
+
+ match &*item.to_lowercase() {
+ "FOO" => {},
+ "BAR" => {},
+ _ => {},
+ }
+}
+
+// Invalid
+
+fn as_str_match_mismatch() {
+ let var = "BAR";
+
+ match var.to_ascii_lowercase().as_str() {
+ "foo" => {},
+ "Bar" => {},
+ _ => {},
+ }
+}
+
+fn addrof_unary_match_mismatch() {
+ let var = "BAR";
+
+ match &*var.to_ascii_lowercase() {
+ "foo" => {},
+ "Bar" => {},
+ _ => {},
+ }
+}
+
+fn alternating_chain_mismatch() {
+ let var = "BAR";
+
+ match &*var
+ .to_ascii_lowercase()
+ .to_uppercase()
+ .to_lowercase()
+ .to_ascii_uppercase()
+ {
+ "FOO" => {},
+ "bAR" => {},
+ _ => {},
+ }
+}
+
+fn main() {}
--- /dev/null
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:68:9
+ |
+LL | "Bar" => {},
+ | ^^^^^
+ |
+ = note: `-D clippy::match-str-case-mismatch` implied by `-D warnings`
+help: consider changing the case of this arm to respect `to_ascii_lowercase`
+ |
+LL | "bar" => {},
+ | ~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:78:9
+ |
+LL | "Bar" => {},
+ | ^^^^^
+ |
+help: consider changing the case of this arm to respect `to_ascii_lowercase`
+ |
+LL | "bar" => {},
+ | ~~~~~
+
+error: this `match` arm has a differing case than its expression
+ --> $DIR/match_str_case_mismatch.rs:93:9
+ |
+LL | "bAR" => {},
+ | ^^^^^
+ |
+help: consider changing the case of this arm to respect `to_ascii_uppercase`
+ |
+LL | "BAR" => {},
+ | ~~~~~
+
+error: aborting due to 3 previous errors
+
+// aux-build:macro_rules.rs
+
#![allow(unused, clippy::no_effect, clippy::unnecessary_operation)]
#![warn(clippy::mut_mut)]
+#[macro_use]
+extern crate macro_rules;
+
fn fun(x: &mut &mut u32) -> bool {
**x > 0
}
println!(":{}", arg);
}
}
+
+fn issue6922() {
+ // do not lint from an external macro
+ mut_mut!();
+}
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:4:11
+ --> $DIR/mut_mut.rs:9:11
|
LL | fn fun(x: &mut &mut u32) -> bool {
| ^^^^^^^^^^^^^
= note: `-D clippy::mut-mut` implied by `-D warnings`
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:20:17
+ --> $DIR/mut_mut.rs:25:17
|
LL | let mut x = &mut &mut 1u32;
| ^^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:14:9
+ --> $DIR/mut_mut.rs:19:9
|
LL | &mut $p
| ^^^^^^^
= note: this error originates in the macro `mut_ptr` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this expression mutably borrows a mutable reference. Consider reborrowing
- --> $DIR/mut_mut.rs:22:21
+ --> $DIR/mut_mut.rs:27:21
|
LL | let mut y = &mut x;
| ^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:26:32
+ --> $DIR/mut_mut.rs:31:32
|
LL | let y: &mut &mut u32 = &mut &mut 2;
| ^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:26:16
+ --> $DIR/mut_mut.rs:31:16
|
LL | let y: &mut &mut u32 = &mut &mut 2;
| ^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:31:37
+ --> $DIR/mut_mut.rs:36:37
|
LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2;
| ^^^^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:31:16
+ --> $DIR/mut_mut.rs:36:16
|
LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2;
| ^^^^^^^^^^^^^^^^^^
error: generally you want to avoid `&mut &mut _` if possible
- --> $DIR/mut_mut.rs:31:21
+ --> $DIR/mut_mut.rs:36:21
|
LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2;
| ^^^^^^^^^^^^^
#![feature(box_syntax)]
-#![warn(clippy::no_effect)]
+#![warn(clippy::no_effect_underscore_binding)]
#![allow(dead_code)]
#![allow(path_statements)]
#![allow(clippy::deref_addrof)]
|| x += 5;
let s: String = "foo".into();
FooString { s: s };
+ let _unused = 1;
+ let _penguin = || println!("Some helpful closure");
+ let _duck = Struct { field: 0 };
+ let _cat = [2, 4, 6, 8][2];
#[allow(clippy::no_effect)]
0;
// Do not warn
get_number();
unsafe { unsafe_fn() };
+ let _used = get_struct();
+ let _x = vec![1];
DropUnit;
DropStruct { field: 0 };
DropTuple(0);
LL | FooString { s: s };
| ^^^^^^^^^^^^^^^^^^^
-error: aborting due to 26 previous errors
+error: binding to `_` prefixed variable with no side-effect
+ --> $DIR/no_effect.rs:93:5
+ |
+LL | let _unused = 1;
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::no-effect-underscore-binding` implied by `-D warnings`
+
+error: binding to `_` prefixed variable with no side-effect
+ --> $DIR/no_effect.rs:94:5
+ |
+LL | let _penguin = || println!("Some helpful closure");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: binding to `_` prefixed variable with no side-effect
+ --> $DIR/no_effect.rs:95:5
+ |
+LL | let _duck = Struct { field: 0 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: binding to `_` prefixed variable with no side-effect
+ --> $DIR/no_effect.rs:96:5
+ |
+LL | let _cat = [2, 4, 6, 8][2];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 30 previous errors
|
help: try
|
-LL | let _ = a == b && c == 5;
- | ~~~~~~~~~~~~~~~~
LL | let _ = !(a != b || c != 5);
| ~~~~~~~~~~~~~~~~~~~
+LL | let _ = a == b && c == 5;
+ | ~~~~~~~~~~~~~~~~
error: this boolean expression can be simplified
--> $DIR/nonminimal_bool.rs:28:13
|
help: try
|
-LL | let _ = a == b || c == 5;
- | ~~~~~~~~~~~~~~~~
LL | let _ = !(a != b && c != 5);
| ~~~~~~~~~~~~~~~~~~~
+LL | let _ = a == b || c == 5;
+ | ~~~~~~~~~~~~~~~~
error: this boolean expression can be simplified
--> $DIR/nonminimal_bool.rs:29:13
|
help: try
|
-LL | let _ = a == b && c == 5;
- | ~~~~~~~~~~~~~~~~
LL | let _ = !(a != b || c != 5);
| ~~~~~~~~~~~~~~~~~~~
+LL | let _ = a == b && c == 5;
+ | ~~~~~~~~~~~~~~~~
error: this boolean expression can be simplified
--> $DIR/nonminimal_bool.rs:30:13
|
help: try
|
-LL | let _ = a != b || c != d;
- | ~~~~~~~~~~~~~~~~
LL | let _ = !(a == b && c == d);
| ~~~~~~~~~~~~~~~~~~~
+LL | let _ = a != b || c != d;
+ | ~~~~~~~~~~~~~~~~
error: this boolean expression can be simplified
--> $DIR/nonminimal_bool.rs:31:13
|
help: try
|
-LL | let _ = a != b && c != d;
- | ~~~~~~~~~~~~~~~~
LL | let _ = !(a == b || c == d);
| ~~~~~~~~~~~~~~~~~~~
+LL | let _ = a != b && c != d;
+ | ~~~~~~~~~~~~~~~~
error: aborting due to 12 previous errors
// edition:2018
// run-rustfix
#![warn(clippy::option_if_let_else)]
-#![allow(clippy::redundant_closure)]
-#![allow(clippy::ref_option_ref, clippy::equatable_if_let)]
+#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)]
fn bad1(string: Option<&str>) -> (bool, &str) {
string.map_or((false, "hello"), |x| (true, x))
// edition:2018
// run-rustfix
#![warn(clippy::option_if_let_else)]
-#![allow(clippy::redundant_closure)]
-#![allow(clippy::ref_option_ref, clippy::equatable_if_let)]
+#![allow(clippy::redundant_closure, clippy::ref_option_ref, clippy::equatable_if_let)]
fn bad1(string: Option<&str>) -> (bool, &str) {
if let Some(x) = string {
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:8:5
+ --> $DIR/option_if_let_else.rs:7: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:26:13
+ --> $DIR/option_if_let_else.rs:25: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:27:13
+ --> $DIR/option_if_let_else.rs:26: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:28:13
+ --> $DIR/option_if_let_else.rs:27: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:34:13
+ --> $DIR/option_if_let_else.rs:33: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:35:13
+ --> $DIR/option_if_let_else.rs:34: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:41:13
+ --> $DIR/option_if_let_else.rs:40: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:50:5
+ --> $DIR/option_if_let_else.rs:49: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:63:13
+ --> $DIR/option_if_let_else.rs:62: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:72:13
+ --> $DIR/option_if_let_else.rs:71: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:101:13
+ --> $DIR/option_if_let_else.rs:100: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:110:13
+ --> $DIR/option_if_let_else.rs:109: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:138:13
+ --> $DIR/option_if_let_else.rs:137: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:142:13
+ --> $DIR/option_if_let_else.rs:141:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
Some(0)
}
+fn result_func(x: Result<i32, &str>) -> Result<i32, &str> {
+ let _ = x?;
+
+ x?;
+
+ // No warning
+ let y = if let Ok(x) = x {
+ x
+ } else {
+ return Err("some error");
+ };
+
+ Ok(y)
+}
+
fn main() {
some_func(Some(42));
some_func(None);
returns_something_similar_to_option(so);
func();
+
+ let _ = result_func(Ok(42));
}
Some(0)
}
+fn result_func(x: Result<i32, &str>) -> Result<i32, &str> {
+ let _ = if let Ok(x) = x { x } else { return x };
+
+ if x.is_err() {
+ return x;
+ }
+
+ // No warning
+ let y = if let Ok(x) = x {
+ x
+ } else {
+ return Err("some error");
+ };
+
+ Ok(y)
+}
+
fn main() {
some_func(Some(42));
some_func(None);
returns_something_similar_to_option(so);
func();
+
+ let _ = result_func(Ok(42));
}
LL | | }
| |_____^ help: replace it with: `f()?;`
-error: aborting due to 11 previous errors
+error: this if-let-else may be rewritten with the `?` operator
+ --> $DIR/question_mark.rs:138: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
+ |
+LL | / if x.is_err() {
+LL | | return x;
+LL | | }
+ | |_____^ help: replace it with: `x?;`
+
+error: aborting due to 13 previous errors
let mut s = MaybeUninit::<String>::uninit();
let _d = || unsafe { ptr::drop_in_place(s.as_mut_ptr()) };
}
+
+// Issue #7768
+#[rustfmt::skip]
+fn macro_with_semicolon() {
+ macro_rules! repro {
+ () => {
+ while false {
+ }
+ };
+ }
+ repro!();
+}
let x = foo(x);
let x = || x;
let x = Some(1).map(|_| x)?;
+ let y = 1;
+ let y = match y {
+ 1 => 2,
+ _ => 3,
+ };
None
}
LL | let x = &mut x;
| ^
-error: `x` is shadowed by `x.0` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:13:9
|
LL | let x = x.0;
LL | let x = ([[0]], ());
| ^
-error: `x` is shadowed by `x[0]` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:14:9
|
LL | let x = x[0];
LL | let x = x.0;
| ^
-error: `x` is shadowed by `x` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:15:10
|
LL | let [x] = x;
LL | let x = x[0];
| ^
-error: `x` is shadowed by `Some(x)` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:16:9
|
LL | let x = Some(x);
LL | let [x] = x;
| ^
-error: `x` is shadowed by `foo(x)` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:17:9
|
LL | let x = foo(x);
LL | let x = Some(x);
| ^
-error: `x` is shadowed by `|| x` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:18:9
|
LL | let x = || x;
LL | let x = foo(x);
| ^
-error: `x` is shadowed by `Some(1).map(|_| x)?` which reuses the original value
+error: `x` is shadowed
--> $DIR/shadow.rs:19:9
|
LL | let x = Some(1).map(|_| x)?;
LL | let x = || x;
| ^
+error: `y` is shadowed
+ --> $DIR/shadow.rs:21:9
+ |
+LL | let y = match y {
+ | ^
+ |
+note: previous binding is here
+ --> $DIR/shadow.rs:20:9
+ |
+LL | let y = 1;
+ | ^
+
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:25:9
+ --> $DIR/shadow.rs:30:9
|
LL | let x = 2;
| ^
|
= note: `-D clippy::shadow-unrelated` implied by `-D warnings`
note: previous binding is here
- --> $DIR/shadow.rs:24:9
+ --> $DIR/shadow.rs:29:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:30:13
+ --> $DIR/shadow.rs:35:13
|
LL | let x = 1;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:29:10
+ --> $DIR/shadow.rs:34:10
|
LL | fn f(x: u32) {
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:35:14
+ --> $DIR/shadow.rs:40:14
|
LL | Some(x) => {
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:32:9
+ --> $DIR/shadow.rs:37:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:36:17
+ --> $DIR/shadow.rs:41:17
|
LL | let x = 1;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:35:14
+ --> $DIR/shadow.rs:40:14
|
LL | Some(x) => {
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:40:17
+ --> $DIR/shadow.rs:45:17
|
LL | if let Some(x) = Some(1) {}
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:32:9
+ --> $DIR/shadow.rs:37:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:41:20
+ --> $DIR/shadow.rs:46:20
|
LL | while let Some(x) = Some(1) {}
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:32:9
+ --> $DIR/shadow.rs:37:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:42:15
+ --> $DIR/shadow.rs:47:15
|
LL | let _ = |[x]: [u32; 1]| {
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:32:9
+ --> $DIR/shadow.rs:37:9
|
LL | let x = 1;
| ^
error: `x` shadows a previous, unrelated binding
- --> $DIR/shadow.rs:43:13
+ --> $DIR/shadow.rs:48:13
|
LL | let x = 1;
| ^
|
note: previous binding is here
- --> $DIR/shadow.rs:42:15
+ --> $DIR/shadow.rs:47:15
|
LL | let _ = |[x]: [u32; 1]| {
| ^
-error: aborting due to 19 previous errors
+error: aborting due to 20 previous errors
#![warn(clippy::to_string_in_display)]
-#![allow(clippy::inherent_to_string_shadow_display)]
+#![allow(clippy::inherent_to_string_shadow_display, clippy::to_string_in_format_args)]
use std::fmt;
--- /dev/null
+#![warn(clippy::trailing_empty_array)]
+#![feature(const_generics_defaults)]
+
+// Do lint:
+
+struct RarelyUseful {
+ field: i32,
+ last: [usize; 0],
+}
+
+struct OnlyField {
+ first_and_last: [usize; 0],
+}
+
+struct GenericArrayType<T> {
+ field: i32,
+ last: [T; 0],
+}
+
+#[must_use]
+struct OnlyAnotherAttribute {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[derive(Debug)]
+struct OnlyADeriveAttribute {
+ field: i32,
+ last: [usize; 0],
+}
+
+const ZERO: usize = 0;
+struct ZeroSizedWithConst {
+ field: i32,
+ last: [usize; ZERO],
+}
+
+#[allow(clippy::eq_op)]
+const fn compute_zero() -> usize {
+ (4 + 6) - (2 * 5)
+}
+struct ZeroSizedWithConstFunction {
+ field: i32,
+ last: [usize; compute_zero()],
+}
+
+const fn compute_zero_from_arg(x: usize) -> usize {
+ x - 1
+}
+struct ZeroSizedWithConstFunction2 {
+ field: i32,
+ last: [usize; compute_zero_from_arg(1)],
+}
+
+struct ZeroSizedArrayWrapper([usize; 0]);
+
+struct TupleStruct(i32, [usize; 0]);
+
+struct LotsOfFields {
+ f1: u32,
+ f2: u32,
+ f3: u32,
+ f4: u32,
+ f5: u32,
+ f6: u32,
+ f7: u32,
+ f8: u32,
+ f9: u32,
+ f10: u32,
+ f11: u32,
+ f12: u32,
+ f13: u32,
+ f14: u32,
+ f15: u32,
+ f16: u32,
+ last: [usize; 0],
+}
+
+// Don't lint
+
+#[repr(C)]
+struct GoodReason {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[repr(C)]
+struct OnlyFieldWithReprC {
+ first_and_last: [usize; 0],
+}
+
+struct NonZeroSizedArray {
+ field: i32,
+ last: [usize; 1],
+}
+
+struct NotLastField {
+ f1: u32,
+ zero_sized: [usize; 0],
+ last: i32,
+}
+
+const ONE: usize = 1;
+struct NonZeroSizedWithConst {
+ field: i32,
+ last: [usize; ONE],
+}
+
+#[derive(Debug)]
+#[repr(C)]
+struct AlsoADeriveAttribute {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[must_use]
+#[repr(C)]
+struct AlsoAnotherAttribute {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[repr(packed)]
+struct ReprPacked {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[repr(C, packed)]
+struct ReprCPacked {
+ field: i32,
+ last: [usize; 0],
+}
+
+#[repr(align(64))]
+struct ReprAlign {
+ field: i32,
+ last: [usize; 0],
+}
+#[repr(C, align(64))]
+struct ReprCAlign {
+ field: i32,
+ last: [usize; 0],
+}
+
+// NOTE: because of https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representation-of-enums-with-fields and I'm not sure when in the compilation pipeline that would happen
+#[repr(C)]
+enum DontLintAnonymousStructsFromDesuraging {
+ A(u32),
+ B(f32, [u64; 0]),
+ C { x: u32, y: [u64; 0] },
+}
+
+#[repr(C)]
+struct TupleStructReprC(i32, [usize; 0]);
+
+type NamedTuple = (i32, [usize; 0]);
+
+#[rustfmt::skip] // [rustfmt#4995](https://github.com/rust-lang/rustfmt/issues/4995)
+struct ConstParamZeroDefault<const N: usize = 0> {
+ field: i32,
+ last: [usize; N],
+}
+
+struct ConstParamNoDefault<const N: usize> {
+ field: i32,
+ last: [usize; N],
+}
+
+#[rustfmt::skip]
+struct ConstParamNonZeroDefault<const N: usize = 1> {
+ field: i32,
+ last: [usize; N],
+}
+
+struct TwoGenericParams<T, const N: usize> {
+ field: i32,
+ last: [T; N],
+}
+
+type A = ConstParamZeroDefault;
+type B = ConstParamZeroDefault<0>;
+type C = ConstParamNoDefault<0>;
+type D = ConstParamNonZeroDefault<0>;
+
+fn main() {}
--- /dev/null
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:6:1
+ |
+LL | / struct RarelyUseful {
+LL | | field: i32,
+LL | | last: [usize; 0],
+LL | | }
+ | |_^
+ |
+ = note: `-D clippy::trailing-empty-array` implied by `-D warnings`
+ = help: consider annotating `RarelyUseful` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:11:1
+ |
+LL | / struct OnlyField {
+LL | | first_and_last: [usize; 0],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `OnlyField` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:15:1
+ |
+LL | / struct GenericArrayType<T> {
+LL | | field: i32,
+LL | | last: [T; 0],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `GenericArrayType` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:21:1
+ |
+LL | / struct OnlyAnotherAttribute {
+LL | | field: i32,
+LL | | last: [usize; 0],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `OnlyAnotherAttribute` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:27:1
+ |
+LL | / struct OnlyADeriveAttribute {
+LL | | field: i32,
+LL | | last: [usize; 0],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `OnlyADeriveAttribute` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:33:1
+ |
+LL | / struct ZeroSizedWithConst {
+LL | | field: i32,
+LL | | last: [usize; ZERO],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `ZeroSizedWithConst` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:42:1
+ |
+LL | / struct ZeroSizedWithConstFunction {
+LL | | field: i32,
+LL | | last: [usize; compute_zero()],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `ZeroSizedWithConstFunction` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:50:1
+ |
+LL | / struct ZeroSizedWithConstFunction2 {
+LL | | field: i32,
+LL | | last: [usize; compute_zero_from_arg(1)],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `ZeroSizedWithConstFunction2` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:55:1
+ |
+LL | struct ZeroSizedArrayWrapper([usize; 0]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider annotating `ZeroSizedArrayWrapper` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:57:1
+ |
+LL | struct TupleStruct(i32, [usize; 0]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider annotating `TupleStruct` with `#[repr(C)]` or another `repr` attribute
+
+error: trailing zero-sized array in a struct which is not marked with a `repr` attribute
+ --> $DIR/trailing_empty_array.rs:59:1
+ |
+LL | / struct LotsOfFields {
+LL | | f1: u32,
+LL | | f2: u32,
+LL | | f3: u32,
+... |
+LL | | last: [usize; 0],
+LL | | }
+ | |_^
+ |
+ = help: consider annotating `LotsOfFields` with `#[repr(C)]` or another `repr` attribute
+
+error: aborting due to 11 previous errors
+
}
}
+mod num_to_bytes {
+ fn test() {
+ unsafe {
+ let _: [u8; 1] = std::mem::transmute(0u8);
+ let _: [u8; 4] = std::mem::transmute(0u32);
+ let _: [u8; 16] = std::mem::transmute(0u128);
+ let _: [u8; 1] = std::mem::transmute(0i8);
+ let _: [u8; 4] = std::mem::transmute(0i32);
+ let _: [u8; 16] = std::mem::transmute(0i128);
+ let _: [u8; 4] = std::mem::transmute(0.0f32);
+ let _: [u8; 8] = std::mem::transmute(0.0f64);
+ }
+ }
+ const fn test_const() {
+ unsafe {
+ let _: [u8; 1] = std::mem::transmute(0u8);
+ let _: [u8; 4] = std::mem::transmute(0u32);
+ let _: [u8; 16] = std::mem::transmute(0u128);
+ let _: [u8; 1] = std::mem::transmute(0i8);
+ let _: [u8; 4] = std::mem::transmute(0i32);
+ let _: [u8; 16] = std::mem::transmute(0i128);
+ let _: [u8; 4] = std::mem::transmute(0.0f32);
+ let _: [u8; 8] = std::mem::transmute(0.0f64);
+ }
+ }
+}
+
fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
let _: &str = unsafe { std::mem::transmute(b) };
let _: &mut str = unsafe { std::mem::transmute(mb) };
LL | let _: f64 = unsafe { std::mem::transmute(0_i64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
+error: transmute from a `u8` to a `[u8; 1]`
+ --> $DIR/transmute.rs:109:30
+ |
+LL | let _: [u8; 1] = std::mem::transmute(0u8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
+ |
+ = note: `-D clippy::transmute-num-to-bytes` implied by `-D warnings`
+
+error: transmute from a `u32` to a `[u8; 4]`
+ --> $DIR/transmute.rs:110:30
+ |
+LL | let _: [u8; 4] = std::mem::transmute(0u32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
+
+error: transmute from a `u128` to a `[u8; 16]`
+ --> $DIR/transmute.rs:111:31
+ |
+LL | let _: [u8; 16] = std::mem::transmute(0u128);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
+
+error: transmute from a `i8` to a `[u8; 1]`
+ --> $DIR/transmute.rs:112:30
+ |
+LL | let _: [u8; 1] = std::mem::transmute(0i8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
+
+error: transmute from a `i32` to a `[u8; 4]`
+ --> $DIR/transmute.rs:113:30
+ |
+LL | let _: [u8; 4] = std::mem::transmute(0i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
+
+error: transmute from a `i128` to a `[u8; 16]`
+ --> $DIR/transmute.rs:114:31
+ |
+LL | let _: [u8; 16] = std::mem::transmute(0i128);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
+
+error: transmute from a `f32` to a `[u8; 4]`
+ --> $DIR/transmute.rs:115:30
+ |
+LL | let _: [u8; 4] = std::mem::transmute(0.0f32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
+
+error: transmute from a `f64` to a `[u8; 8]`
+ --> $DIR/transmute.rs:116:30
+ |
+LL | let _: [u8; 8] = std::mem::transmute(0.0f64);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
+
+error: transmute from a `u8` to a `[u8; 1]`
+ --> $DIR/transmute.rs:121:30
+ |
+LL | let _: [u8; 1] = std::mem::transmute(0u8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
+
+error: transmute from a `u32` to a `[u8; 4]`
+ --> $DIR/transmute.rs:122:30
+ |
+LL | let _: [u8; 4] = std::mem::transmute(0u32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
+
+error: transmute from a `u128` to a `[u8; 16]`
+ --> $DIR/transmute.rs:123:31
+ |
+LL | let _: [u8; 16] = std::mem::transmute(0u128);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
+
+error: transmute from a `i8` to a `[u8; 1]`
+ --> $DIR/transmute.rs:124:30
+ |
+LL | let _: [u8; 1] = std::mem::transmute(0i8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
+
+error: transmute from a `i32` to a `[u8; 4]`
+ --> $DIR/transmute.rs:125:30
+ |
+LL | let _: [u8; 4] = std::mem::transmute(0i32);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
+
+error: transmute from a `i128` to a `[u8; 16]`
+ --> $DIR/transmute.rs:126:31
+ |
+LL | let _: [u8; 16] = std::mem::transmute(0i128);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
+
error: transmute from a `&[u8]` to a `&str`
- --> $DIR/transmute.rs:107:28
+ --> $DIR/transmute.rs:134:28
|
LL | let _: &str = unsafe { std::mem::transmute(b) };
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(b).unwrap()`
= note: `-D clippy::transmute-bytes-to-str` implied by `-D warnings`
error: transmute from a `&mut [u8]` to a `&mut str`
- --> $DIR/transmute.rs:108:32
+ --> $DIR/transmute.rs:135:32
|
LL | let _: &mut str = unsafe { std::mem::transmute(mb) };
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
-error: aborting due to 24 previous errors
+error: aborting due to 38 previous errors
--- /dev/null
+#![warn(clippy::undocumented_unsafe_blocks)]
+
+// Valid comments
+
+fn nested_local() {
+ let _ = {
+ let _ = {
+ // Safety:
+ let _ = unsafe {};
+ };
+ };
+}
+
+fn deep_nest() {
+ let _ = {
+ let _ = {
+ // Safety:
+ let _ = unsafe {};
+
+ // Safety:
+ unsafe {};
+
+ let _ = {
+ let _ = {
+ let _ = {
+ let _ = {
+ let _ = {
+ // Safety:
+ let _ = unsafe {};
+
+ // Safety:
+ unsafe {};
+ };
+ };
+ };
+
+ // Safety:
+ unsafe {};
+ };
+ };
+ };
+
+ // Safety:
+ unsafe {};
+ };
+
+ // Safety:
+ unsafe {};
+}
+
+fn local_tuple_expression() {
+ // Safety:
+ let _ = (42, unsafe {});
+}
+
+fn line_comment() {
+ // Safety:
+ unsafe {}
+}
+
+fn line_comment_newlines() {
+ // Safety:
+
+ unsafe {}
+}
+
+fn line_comment_empty() {
+ // Safety:
+ //
+ //
+ //
+ unsafe {}
+}
+
+fn line_comment_with_extras() {
+ // This is a description
+ // Safety:
+ unsafe {}
+}
+
+fn block_comment() {
+ /* Safety: */
+ unsafe {}
+}
+
+fn block_comment_newlines() {
+ /* Safety: */
+
+ unsafe {}
+}
+
+#[rustfmt::skip]
+fn inline_block_comment() {
+ /* Safety: */unsafe {}
+}
+
+fn block_comment_with_extras() {
+ /* This is a description
+ * Safety:
+ */
+ unsafe {}
+}
+
+fn block_comment_terminator_same_line() {
+ /* This is a description
+ * Safety: */
+ unsafe {}
+}
+
+fn buried_safety() {
+ // Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
+ // incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
+ // ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
+ // reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
+ // occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
+ // laborum. Safety:
+ // Tellus elementum sagittis vitae et leo duis ut diam quam. Sit amet nulla facilisi
+ // morbi tempus iaculis urna. Amet luctus venenatis lectus magna. At quis risus sed vulputate odio
+ // ut. Luctus venenatis lectus magna fringilla urna. Tortor id aliquet lectus proin nibh nisl
+ // condimentum id venenatis. Vulputate dignissim suspendisse in est ante in nibh mauris cursus.
+ unsafe {}
+}
+
+fn safety_with_prepended_text() {
+ // This is a test. Safety:
+ unsafe {}
+}
+
+fn local_line_comment() {
+ // Safety:
+ let _ = unsafe {};
+}
+
+fn local_block_comment() {
+ /* Safety: */
+ let _ = unsafe {};
+}
+
+fn comment_array() {
+ // Safety:
+ let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+}
+
+fn comment_tuple() {
+ // Safety:
+ let _ = (42, unsafe {}, "test", unsafe {});
+}
+
+fn comment_unary() {
+ // Safety:
+ let _ = *unsafe { &42 };
+}
+
+#[allow(clippy::match_single_binding)]
+fn comment_match() {
+ // Safety:
+ let _ = match unsafe {} {
+ _ => {},
+ };
+}
+
+fn comment_addr_of() {
+ // Safety:
+ let _ = &unsafe {};
+}
+
+fn comment_repeat() {
+ // Safety:
+ let _ = [unsafe {}; 5];
+}
+
+fn comment_macro_call() {
+ macro_rules! t {
+ ($b:expr) => {
+ $b
+ };
+ }
+
+ t!(
+ // Safety:
+ unsafe {}
+ );
+}
+
+fn comment_macro_def() {
+ macro_rules! t {
+ () => {
+ // Safety:
+ unsafe {}
+ };
+ }
+
+ t!();
+}
+
+fn non_ascii_comment() {
+ // ॐ᧻໒ Safety: ௵∰
+ unsafe {};
+}
+
+fn local_commented_block() {
+ let _ =
+ // Safety:
+ unsafe {};
+}
+
+fn local_nest() {
+ // Safety:
+ let _ = [(42, unsafe {}, unsafe {}), (52, unsafe {}, unsafe {})];
+}
+
+// Invalid comments
+
+fn no_comment() {
+ unsafe {}
+}
+
+fn no_comment_array() {
+ let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+}
+
+fn no_comment_tuple() {
+ let _ = (42, unsafe {}, "test", unsafe {});
+}
+
+fn no_comment_unary() {
+ let _ = *unsafe { &42 };
+}
+
+#[allow(clippy::match_single_binding)]
+fn no_comment_match() {
+ let _ = match unsafe {} {
+ _ => {},
+ };
+}
+
+fn no_comment_addr_of() {
+ let _ = &unsafe {};
+}
+
+fn no_comment_repeat() {
+ let _ = [unsafe {}; 5];
+}
+
+fn local_no_comment() {
+ let _ = unsafe {};
+}
+
+fn no_comment_macro_call() {
+ macro_rules! t {
+ ($b:expr) => {
+ $b
+ };
+ }
+
+ t!(unsafe {});
+}
+
+fn no_comment_macro_def() {
+ macro_rules! t {
+ () => {
+ unsafe {}
+ };
+ }
+
+ t!();
+}
+
+fn trailing_comment() {
+ unsafe {} // Safety:
+}
+
+fn internal_comment() {
+ unsafe {
+ // Safety:
+ }
+}
+
+fn interference() {
+ // Safety
+
+ let _ = 42;
+
+ unsafe {};
+}
+
+fn main() {}
--- /dev/null
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:215:5
+ |
+LL | unsafe {}
+ | ^^^^^^^^^
+ |
+ = note: `-D clippy::undocumented-unsafe-blocks` implied by `-D warnings`
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + unsafe {}
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:219:5
+ |
+LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }];
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:223:5
+ |
+LL | let _ = (42, unsafe {}, "test", unsafe {});
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = (42, unsafe {}, "test", unsafe {});
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:227:5
+ |
+LL | let _ = *unsafe { &42 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = *unsafe { &42 };
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:232:5
+ |
+LL | let _ = match unsafe {} {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = match unsafe {} {
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:238:5
+ |
+LL | let _ = &unsafe {};
+ | ^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = &unsafe {};
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:242:5
+ |
+LL | let _ = [unsafe {}; 5];
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = [unsafe {}; 5];
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:246:5
+ |
+LL | let _ = unsafe {};
+ | ^^^^^^^^^^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + let _ = unsafe {};
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:256:8
+ |
+LL | t!(unsafe {});
+ | ^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ t!(// Safety: ...
+LL ~ unsafe {});
+ |
+
+error: unsafe block in macro expansion missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:262:13
+ |
+LL | unsafe {}
+ | ^^^^^^^^^
+...
+LL | t!();
+ | ---- in this macro invocation
+ |
+ = help: consider adding a safety comment in the macro definition
+ = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:270:5
+ |
+LL | unsafe {} // Safety:
+ | ^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL ~ unsafe {} // Safety:
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:274:5
+ |
+LL | unsafe {
+ | ^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL + unsafe {
+ |
+
+error: unsafe block missing a safety comment
+ --> $DIR/undocumented_unsafe_blocks.rs:284:5
+ |
+LL | unsafe {};
+ | ^^^^^^^^^
+ |
+help: consider adding a safety comment
+ |
+LL ~ // Safety: ...
+LL ~ unsafe {};
+ |
+
+error: aborting due to 13 previous errors
+
--- /dev/null
+#![warn(clippy::uninit_vec)]
+
+use std::mem::MaybeUninit;
+
+#[derive(Default)]
+struct MyVec {
+ vec: Vec<u8>,
+}
+
+fn main() {
+ // with_capacity() -> set_len() should be detected
+ let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ unsafe {
+ vec.set_len(200);
+ }
+
+ // reserve() -> set_len() should be detected
+ vec.reserve(1000);
+ unsafe {
+ vec.set_len(200);
+ }
+
+ // new() -> set_len() should be detected
+ let mut vec: Vec<u8> = Vec::new();
+ unsafe {
+ vec.set_len(200);
+ }
+
+ // default() -> set_len() should be detected
+ let mut vec: Vec<u8> = Default::default();
+ unsafe {
+ vec.set_len(200);
+ }
+
+ let mut vec: Vec<u8> = Vec::default();
+ unsafe {
+ vec.set_len(200);
+ }
+
+ // test when both calls are enclosed in the same unsafe block
+ unsafe {
+ let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ vec.set_len(200);
+
+ vec.reserve(1000);
+ vec.set_len(200);
+ }
+
+ let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ unsafe {
+ // test the case where there are other statements in the following unsafe block
+ vec.set_len(200);
+ assert!(vec.len() == 200);
+ }
+
+ // handle vec stored in the field of a struct
+ let mut my_vec = MyVec::default();
+ my_vec.vec.reserve(1000);
+ unsafe {
+ my_vec.vec.set_len(200);
+ }
+
+ my_vec.vec = Vec::with_capacity(1000);
+ unsafe {
+ my_vec.vec.set_len(200);
+ }
+
+ // Test `#[allow(...)]` attributes on inner unsafe block (shouldn't trigger)
+ let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ #[allow(clippy::uninit_vec)]
+ unsafe {
+ vec.set_len(200);
+ }
+
+ // MaybeUninit-wrapped types should not be detected
+ unsafe {
+ let mut vec: Vec<MaybeUninit<u8>> = Vec::with_capacity(1000);
+ vec.set_len(200);
+
+ let mut vec: Vec<(MaybeUninit<u8>, MaybeUninit<bool>)> = Vec::with_capacity(1000);
+ vec.set_len(200);
+
+ let mut vec: Vec<(MaybeUninit<u8>, [MaybeUninit<bool>; 2])> = Vec::with_capacity(1000);
+ vec.set_len(200);
+ }
+
+ // known false negative
+ let mut vec1: Vec<u8> = Vec::with_capacity(1000);
+ let mut vec2: Vec<u8> = Vec::with_capacity(1000);
+ unsafe {
+ vec1.set_len(200);
+ vec2.set_len(200);
+ }
+}
--- /dev/null
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:12:5
+ |
+LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::uninit-vec` implied by `-D warnings`
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:18:5
+ |
+LL | vec.reserve(1000);
+ | ^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` on empty `Vec` creates out-of-bound values
+ --> $DIR/uninit_vec.rs:24:5
+ |
+LL | let mut vec: Vec<u8> = Vec::new();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+
+error: calling `set_len()` on empty `Vec` creates out-of-bound values
+ --> $DIR/uninit_vec.rs:30:5
+ |
+LL | let mut vec: Vec<u8> = Default::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+
+error: calling `set_len()` on empty `Vec` creates out-of-bound values
+ --> $DIR/uninit_vec.rs:35:5
+ |
+LL | let mut vec: Vec<u8> = Vec::default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:49:5
+ |
+LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:58:5
+ |
+LL | my_vec.vec.reserve(1000);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | my_vec.vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:63:5
+ |
+LL | my_vec.vec = Vec::with_capacity(1000);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | unsafe {
+LL | my_vec.vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:42:9
+ |
+LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> $DIR/uninit_vec.rs:45:9
+ |
+LL | vec.reserve(1000);
+ | ^^^^^^^^^^^^^^^^^^
+LL | vec.set_len(200);
+ | ^^^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: aborting due to 10 previous errors
+
#![allow(clippy::stable_sort_primitive)]
+use std::cell::Ref;
use std::cmp::Reverse;
fn unnecessary_sort_by() {
// `Reverse(b)` would borrow in the following cases, don't lint
vec.sort_by(|a, b| b.cmp(a));
vec.sort_unstable_by(|a, b| b.cmp(a));
+
+ // No warning if element does not implement `Ord`
+ let mut vec: Vec<Ref<usize>> = Vec::new();
+ vec.sort_unstable_by(|a, b| a.cmp(b));
}
// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
#![allow(clippy::stable_sort_primitive)]
+use std::cell::Ref;
use std::cmp::Reverse;
fn unnecessary_sort_by() {
// `Reverse(b)` would borrow in the following cases, don't lint
vec.sort_by(|a, b| b.cmp(a));
vec.sort_unstable_by(|a, b| b.cmp(a));
+
+ // No warning if element does not implement `Ord`
+ let mut vec: Vec<Ref<usize>> = Vec::new();
+ vec.sort_unstable_by(|a, b| a.cmp(b));
}
// Do not suggest returning a reference to the closure parameter of `Vec::sort_by_key`
error: use Vec::sort here instead
- --> $DIR/unnecessary_sort_by.rs:14:5
+ --> $DIR/unnecessary_sort_by.rs:15:5
|
LL | vec.sort_by(|a, b| a.cmp(b));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort()`
= note: `-D clippy::unnecessary-sort-by` implied by `-D warnings`
error: use Vec::sort here instead
- --> $DIR/unnecessary_sort_by.rs:15:5
+ --> $DIR/unnecessary_sort_by.rs:16:5
|
LL | vec.sort_unstable_by(|a, b| a.cmp(b));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:16:5
+ --> $DIR/unnecessary_sort_by.rs:17:5
|
LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (a + 5).abs())`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:17:5
+ --> $DIR/unnecessary_sort_by.rs:18:5
|
LL | vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:20:5
+ --> $DIR/unnecessary_sort_by.rs:21:5
|
LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| Reverse((b + 5).abs()))`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:21:5
+ --> $DIR/unnecessary_sort_by.rs:22:5
|
LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a)));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|b| Reverse(id(-b)))`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:31:5
+ --> $DIR/unnecessary_sort_by.rs:32:5
|
LL | vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:32:5
+ --> $DIR/unnecessary_sort_by.rs:33:5
|
LL | vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:88:9
+ --> $DIR/unnecessary_sort_by.rs:93:9
|
LL | args.sort_by(|a, b| a.name().cmp(&b.name()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:89:9
+ --> $DIR/unnecessary_sort_by.rs:94:9
|
LL | args.sort_unstable_by(|a, b| a.name().cmp(&b.name()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:91:9
+ --> $DIR/unnecessary_sort_by.rs:96:9
|
LL | args.sort_by(|a, b| b.name().cmp(&a.name()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|b| Reverse(b.name()))`
error: use Vec::sort_by_key here instead
- --> $DIR/unnecessary_sort_by.rs:92:9
+ --> $DIR/unnecessary_sort_by.rs:97:9
|
LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|b| Reverse(b.name()))`
let _ = foofoo();
}
}
+
+ mod attestation_should_be_replaced {
+ use super::foofoo;
+
+ fn with_explicit() {
+ let _ = foofoo();
+ }
+ }
}
let _ = foofoo();
}
}
+
+ mod attestation_should_be_replaced {
+ use super::*;
+
+ fn with_explicit() {
+ let _ = foofoo();
+ }
+ }
}
LL | use super::super::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
-error: aborting due to 20 previous errors
+error: usage of wildcard import
+ --> $DIR/wildcard_imports.rs:236:13
+ |
+LL | use super::*;
+ | ^^^^^^^^ help: try: `super::foofoo`
+
+error: aborting due to 21 previous errors
--- /dev/null
+#[warn(clippy::eq_op)]
+#[test]
+fn eq_op_shouldnt_trigger_in_tests() {
+ let a = 1;
+ let result = a + 1 == 1 + a;
+ assert!(result);
+}
+
+#[test]
+fn eq_op_macros_shouldnt_trigger_in_tests() {
+ let a = 1;
+ let b = 2;
+ assert_eq!(a, a);
+ assert_eq!(a + b, b + a);
+}
/// The current Rust channel
pub channel: String,
+ /// The default Rust edition
+ pub edition: Option<String>,
+
// Configuration for various run-make tests frobbing things like C compilers
// or querying about various LLVM component information.
pub cc: String,
/// `//[foo]`), then the property is ignored unless `cfg` is
/// `Some("foo")`.
fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
+ let mut has_edition = false;
if !testfile.is_dir() {
let file = File::open(testfile).unwrap();
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());
}
}
}
}
+
+ if let (Some(edition), false) = (&config.edition, has_edition) {
+ self.compile_flags.push(format!("--edition={}", edition));
+ }
}
fn update_fail_mode(&mut self, ln: &str, config: &Config) {
)
.optflag("", "force-rerun", "rerun tests even if the inputs are unchanged")
.optflag("h", "help", "show this message")
- .reqopt("", "channel", "current Rust channel", "CHANNEL");
+ .reqopt("", "channel", "current Rust channel", "CHANNEL")
+ .optopt("", "edition", "default Rust edition", "EDITION");
let (argv0, args_) = args.split_first().unwrap();
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
rustfix_coverage: matches.opt_present("rustfix-coverage"),
has_tidy,
channel: matches.opt_str("channel").unwrap(),
+ edition: matches.opt_str("edition"),
cc: matches.opt_str("cc").unwrap(),
cxx: matches.opt_str("cxx").unwrap(),
("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 1f47693e02809c97db61b51247ae4e4d46744c61
name: upload
on:
+ push:
release:
types: [created]
+ workflow_dispatch:
jobs:
build-release:
- build: linux-x86_64
os: ubuntu-latest
rust: nightly
+ target: x86_64-unknown-linux-gnu
- build: macos-x86_64
os: macos-latest
rust: nightly
+ target: x86_64-apple-darwin
- build: windows-x86_64-gnu
os: windows-latest
rust: nightly-x86_64-gnu
+ target: x86_64-pc-windows-gnu
- build: windows-x86_64-msvc
os: windows-latest
rust: nightly-x86_64-msvc
+ target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- - name: Install Rust
- uses: actions-rs/toolchain@v1
- with:
- profile: minimal
- toolchain: ${{ matrix.rust }}
- override: true
+ # Run build
+ - 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 ${{ matrix.target }}
- name: Add mingw64 to path for x86_64-gnu
run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH
if: matrix.rust == 'nightly-x86_64-gnu'
shell: bash
- - name: Install cargo-make
- uses: actions-rs/cargo@v1
- with:
- command: install
- args: --force cargo-make
-
- name: Build release binaries
uses: actions-rs/cargo@v1
with:
- command: make
- args: release
+ command: build
+ args: --release
- name: Build archive
shell: bash
fi
- name: Upload Release Asset
+ if: github.event_name == 'release'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly'
shell: bash
- - name: cargo-make
- run: cargo install --force cargo-make
-
- name: build
run: |
rustc -Vv
# Generated by Cargo
# will have compiled files and executables
/target
+tests/cargo-fmt/**/target
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
## [Unreleased]
+## [1.4.38] 2021-10-20
+
+### Changed
+
+- Switched from `rustc-ap-*` crates to `rustc_private` for consumption model of rustc internals
+- `annotate-snippets` updated to v0.8 [PR #4762](https://github.com/rust-lang/rustfmt/pull/4762)
+- Greatly improved the performance of `cargo fmt` in large workspaces utilizing the `--all` flag by updating to a newer version of `cargo_metadata` that leverages updated `cargo` output from v1.51+ [PR #4997](https://github.com/rust-lang/rustfmt/pull/4997)
+- Improved formatting of long slice patterns [#4530](https://github.com/rust-lang/rustfmt/issues/4530)
+ - **Note you must have `version = Two` in your configuration to take advantage of the new formatting**
+- Stabilized `match_block_trailing_comma` configuration option [#3380](https://github.com/rust-lang/rustfmt/issues/3380) - [https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#match_block_trailing_comma](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#match_block_trailing_comma)
+- Stabilized `disable_all_formatting` configuration option [#5026](https://github.com/rust-lang/rustfmt/pull/5026) - [https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#disable_all_formatting](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#disable_all_formatting)
+- Various improvements to the configuration documentation website [https://rust-lang.github.io/rustfmt/?version=v1.4.38]([https://rust-lang.github.io/rustfmt/?version=v1.4.38])
+- Addressed various clippy and rustc warnings
+
+
+### Fixed
+
+- Resolved issue where specious whitespace would be inserted when a block style comment was terminated within string literal processing [#4312](https://github.com/rust-lang/rustfmt/issues/4312)
+- Nested out-of-line mods are again parsed and formatted [#4874](https://github.com/rust-lang/rustfmt/issues/4874)
+- Accepts `2021` for edition value from rustfmt command line [PR #4847](https://github.com/rust-lang/rustfmt/pull/4847)
+- Unstable command line options are no longer displayed in `--help` text on stable [PR #4798](https://github.com/rust-lang/rustfmt/issues/4798)
+- Stopped panicking on patterns in match arms which start with non-ascii characters [#4868](https://github.com/rust-lang/rustfmt/issues/4868)
+- Stopped stripping defaults on const params [#4816](https://github.com/rust-lang/rustfmt/issues/4816)
+- Fixed issue with dropped content with GAT aliases with self bounds in impls [#4911](https://github.com/rust-lang/rustfmt/issues/4911)
+- Stopped removing generic args on associated type constraints [#4943](https://github.com/rust-lang/rustfmt/issues/4943)
+- Stopped dropping visibility on certain trait and impl items [#4960](https://github.com/rust-lang/rustfmt/issues/4960)
+- Fixed dropping of qualified paths in struct patterns [#4908](https://github.com/rust-lang/rustfmt/issues/4908) and [#5005](https://github.com/rust-lang/rustfmt/issues/5005)
+- Fixed bug in line width calculation that was causing specious formatting of certain patterns [#4031](https://github.com/rust-lang/rustfmt/issues/4031)
+ - **Note that this bug fix may cause observable formatting changes in cases where code had been formatted with prior versions of rustfmt that contained the bug**
+- Fixed bug where rustfmt would drop parameter attributes if they were too long in certain cases [#4579](https://github.com/rust-lang/rustfmt/issues/4579)
+- Resolved idempotency issue with extern body elements [#4963](https://github.com/rust-lang/rustfmt/issues/4963)
+- rustfmt will now handle doc-style comments on function parameters, since they could appear with certain macro usage patterns even though it's generally invalid syntax [#4936](https://github.com/rust-lang/rustfmt/issues/4936)
+- Fixed bug in `match_block_trailing_comma` where commas were not added to the blocks of bodies whose arm had a guard that did not fit on the same line as the pattern [#4998](https://github.com/rust-lang/rustfmt/pull/4998)
+- Fixed bug in cases where derive attributes started with a block style comment [#4984](https://github.com/rust-lang/rustfmt/issues/4984)
+- Fixed issue where the struct rest could be lost when `struct_field_align_threshold` was enabled [#4926](https://github.com/rust-lang/rustfmt/issues/4926)
+- Handles cases where certain control flow type expressions have comments between patterns/keywords and the pattern ident contains the keyword [#5009](https://github.com/rust-lang/rustfmt/issues/5009)
+- Handles tuple structs that have explicit visibilities and start with a block style comment [#5011](https://github.com/rust-lang/rustfmt/issues/5011)
+- Handles leading line-style comments in certain types of macro calls [#4615](https://github.com/rust-lang/rustfmt/issues/4615)
+
+
+### Added
+- Granular width heuristic options made available for user control [PR #4782](https://github.com/rust-lang/rustfmt/pull/4782). This includes the following:
+ - [`array_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#array_width)
+ - [`attr_fn_like_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#attr_fn_like_width)
+ - [`chain_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#chain_width)
+ - [`fn_call_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#fn_call_width)
+ - [`single_line_if_else_max_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#single_line_if_else_max_width)
+ - [`struct_lit_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#struct_lit_width)
+ - [`struct_variant_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#struct_variant_width)
+
+Note this hit the rustup distributions prior to the v1.4.38 release as part of an out-of-cycle updates, but is listed in this version because the feature was not in the other v1.4.37 releases. See also the `use_small_heuristics` section on the configuration site for more information
+[https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#use_small_heuristics](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#use_small_heuristics)
+
+- New `One` variant added to `imports_granularity` configuration option which can be used to reformat all imports into a single use statement [#4669](https://github.com/rust-lang/rustfmt/issues/4669)
+- rustfmt will now skip files that are annotated with `@generated` at the top of the file [#3958](https://github.com/rust-lang/rustfmt/issues/3958)
+- New configuration option `hex_literal_case` that allows user to control the casing utilized for hex literals [PR #4903](https://github.com/rust-lang/rustfmt/pull/4903)
+
+See the section on the configuration site for more information
+https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#hex_literal_case
+
+- `cargo fmt` now directly supports the `--check` flag, which means it's now possible to run `cargo fmt --check` instead of the more verbose `cargo fmt -- --check` [#3888](https://github.com/rust-lang/rustfmt/issues/3888)
+
+### Install/Download Options
+- **rustup (nightly)** - *pending*
+- **GitHub Release Binaries** - [Release v1.4.38](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.38)
+- **Build from source** - [Tag v1.4.38](https://github.com/rust-lang/rustfmt/tree/v1.4.38), see instructions for how to [install rustfmt from source][install-from-source]
+
## [1.4.37] 2021-04-03
### Changed
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14"
-[[package]]
-name = "arrayref"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
-
-[[package]]
-name = "arrayvec"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
-dependencies = [
- "nodrop",
-]
-
[[package]]
name = "atty"
version = "0.2.13"
[[package]]
name = "autocfg"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
-
-[[package]]
-name = "backtrace"
-version = "0.3.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
-dependencies = [
- "backtrace-sys",
- "cfg-if 0.1.10",
- "libc",
- "rustc-demangle",
-]
-
-[[package]]
-name = "backtrace-sys"
-version = "0.1.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "base64"
-version = "0.10.1"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
-dependencies = [
- "byteorder",
-]
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
-[[package]]
-name = "blake2b_simd"
-version = "0.5.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182"
-dependencies = [
- "arrayref",
- "arrayvec",
- "constant_time_eq",
-]
-
[[package]]
name = "bstr"
version = "0.2.8"
[[package]]
name = "bytecount"
-version = "0.6.0"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e"
+checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
dependencies = [
- "packed_simd",
+ "packed_simd_2",
]
[[package]]
-name = "byteorder"
-version = "1.3.2"
+name = "camino"
+version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
+checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b"
+dependencies = [
+ "serde",
+]
[[package]]
-name = "cargo_metadata"
-version = "0.8.2"
+name = "cargo-platform"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426"
+checksum = "0226944a63d1bf35a3b5f948dd7c59e263db83695c9e8bffc4037de02e30f1d7"
dependencies = [
- "semver",
"serde",
- "serde_derive",
- "serde_json",
]
[[package]]
-name = "cc"
-version = "1.0.46"
+name = "cargo_metadata"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c"
+checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a"
+dependencies = [
+ "camino",
+ "cargo-platform",
+ "semver",
+ "serde",
+ "serde_json",
+]
[[package]]
name = "cfg-if"
"vec_map",
]
-[[package]]
-name = "cloudabi"
-version = "0.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
-name = "constant_time_eq"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
-
-[[package]]
-name = "crossbeam-channel"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c"
-dependencies = [
- "crossbeam-utils 0.7.0",
-]
-
[[package]]
name = "crossbeam-utils"
-version = "0.6.6"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
-dependencies = [
- "cfg-if 0.1.10",
- "lazy_static",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
+checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
dependencies = [
"autocfg",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
"lazy_static",
]
[[package]]
name = "dirs-sys"
-version = "0.3.4"
+version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
+checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780"
dependencies = [
- "cfg-if 0.1.10",
"libc",
"redox_users",
"winapi",
[[package]]
name = "env_logger"
-version = "0.6.2"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
+checksum = "54532e3223c5af90a6a757c90b5c5521564b07e5e7a958681bcd2afad421cdcd"
dependencies = [
"atty",
"humantime",
"termcolor",
]
-[[package]]
-name = "failure"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
-dependencies = [
- "backtrace",
- "failure_derive",
-]
-
-[[package]]
-name = "failure_derive"
-version = "0.1.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
-
[[package]]
name = "fnv"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
-[[package]]
-name = "fuchsia-cprng"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
-
[[package]]
name = "getopts"
version = "0.2.21"
"unicode-width",
]
+[[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "wasi",
+]
+
[[package]]
name = "globset"
-version = "0.4.4"
+version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2"
+checksum = "c152169ef1e421390738366d2f796655fec62621dabbd0fd476f905934061e4a"
dependencies = [
"aho-corasick",
"bstr",
[[package]]
name = "humantime"
-version = "1.3.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
-dependencies = [
- "quick-error",
-]
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "ignore"
-version = "0.4.11"
+version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "522daefc3b69036f80c7d2990b28ff9e0471c683bad05ca258e0a01dd22c5a1e"
+checksum = "b287fb45c60bb826a0dc68ff08742b9d88a2fea13d6e0c286b3172065aaf878c"
dependencies = [
- "crossbeam-channel",
+ "crossbeam-utils",
"globset",
"lazy_static",
"log",
"memchr",
"regex",
"same-file",
- "thread_local 1.0.1",
+ "thread_local",
"walkdir",
"winapi-util",
]
[[package]]
name = "itertools"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
+checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
dependencies = [
"either",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
+[[package]]
+name = "libm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
+
[[package]]
name = "log"
version = "0.4.14"
checksum = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
[[package]]
-name = "nodrop"
-version = "0.1.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
-
-[[package]]
-name = "packed_simd"
-version = "0.3.3"
+name = "packed_simd_2"
+version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
+checksum = "3278e0492f961fd4ae70909f56b2723a7e8d01a228427294e19cdfdebda89a17"
dependencies = [
"cfg-if 0.1.10",
+ "libm",
]
[[package]]
[[package]]
name = "proc-macro2"
-version = "1.0.6"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
+checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid",
]
-[[package]]
-name = "quick-error"
-version = "1.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
-
[[package]]
name = "quote"
version = "1.0.6"
]
[[package]]
-name = "rand_core"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
-dependencies = [
- "rand_core 0.4.2",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
-
-[[package]]
-name = "rand_os"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
-dependencies = [
- "cloudabi",
- "fuchsia-cprng",
- "libc",
- "rand_core 0.4.2",
- "rdrand",
- "winapi",
-]
-
-[[package]]
-name = "rdrand"
-version = "0.4.0"
+name = "redox_syscall"
+version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
+checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570"
dependencies = [
- "rand_core 0.3.1",
+ "bitflags",
]
-[[package]]
-name = "redox_syscall"
-version = "0.1.56"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
-
[[package]]
name = "redox_users"
-version = "0.3.1"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d"
+checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [
- "failure",
- "rand_os",
+ "getrandom",
"redox_syscall",
- "rust-argon2",
]
[[package]]
name = "regex"
-version = "1.3.1"
+version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
+checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
- "thread_local 0.3.6",
+ "thread_local",
]
[[package]]
name = "regex-syntax"
-version = "0.6.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
-
-[[package]]
-name = "rust-argon2"
-version = "0.5.1"
+version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
-dependencies = [
- "base64",
- "blake2b_simd",
- "crossbeam-utils 0.6.6",
-]
-
-[[package]]
-name = "rustc-demangle"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
+checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
[[package]]
name = "rustc-workspace-hack"
[[package]]
name = "rustfmt-nightly"
-version = "1.4.37"
+version = "1.4.38"
dependencies = [
"annotate-snippets",
"anyhow",
[[package]]
name = "semver"
-version = "0.9.0"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
dependencies = [
- "semver-parser",
"serde",
]
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
[[package]]
name = "serde"
-version = "1.0.101"
+version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
+checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.101"
+version = "1.0.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
+checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
dependencies = [
"proc-macro2",
"quote",
[[package]]
name = "serde_json"
-version = "1.0.41"
+version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
+checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95"
dependencies = [
"itoa",
"ryu",
[[package]]
name = "syn"
-version = "1.0.11"
+version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
+checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
-[[package]]
-name = "synstructure"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "unicode-xid",
-]
-
[[package]]
name = "term"
version = "0.6.1"
"syn",
]
-[[package]]
-name = "thread_local"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
-dependencies = [
- "lazy_static",
-]
-
[[package]]
name = "thread_local"
version = "1.0.1"
"winapi-util",
]
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
[[package]]
name = "winapi"
version = "0.3.8"
[package]
name = "rustfmt-nightly"
-version = "1.4.37"
+version = "1.4.38"
description = "Tool to find and fix Rust formatting issues"
repository = "https://github.com/rust-lang/rustfmt"
readme = "README.md"
generic-simd = ["bytecount/generic-simd"]
[dependencies]
-itertools = "0.8"
+itertools = "0.9"
toml = "0.5"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
term = "0.6"
diff = "0.1"
log = "0.4.14"
-env_logger = "0.6"
+env_logger = "0.8"
getopts = "0.2"
derive-new = "0.5"
-cargo_metadata = "0.8"
+cargo_metadata = "0.14"
bytecount = "0.6"
unicode-width = "0.1.5"
unicode_categories = "0.1.1"
dirs = "2.0.1"
-ignore = "0.4.11"
+ignore = "0.4.17"
annotate-snippets = { version = "0.8", features = ["color"] }
structopt = "0.3"
rustfmt-config_proc_macro = { version = "0.2", path = "config_proc_macro" }
## `disable_all_formatting`
-Don't reformat anything
+Don't reformat anything.
+
+Note that this option may be soft-deprecated in the future once the [ignore](#ignore) option is stabilized. Nightly toolchain users are encouraged to use [ignore](#ignore) instead when possible.
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3388)
+- **Stable**: Yes
## `edition`
}
```
+## `format_generated_files`
+
+Format generated files. A file is considered generated
+if any of the first five lines contains `@generated` marker.
+
+- **Default value**: `false`
+- **Possible values**: `true`, `false`
+- **Stable**: No
+
## `format_macro_matchers`
Format the metavariable matching patterns in macros.
See also: [`tab_spaces`](#tab_spaces).
+## `hex_literal_case`
+
+Control the case of the letters in hexadecimal literal values
+
+- **Default value**: `Preserve`
+- **Possible values**: `Upper`, `Lower`
+- **Stable**: No
## `hide_parse_errors`
- **Default value**: `false`
- **Possible values**: `true`, `false`
-- **Stable**: No (tracking issue: #3380)
+- **Stable**: Yes
#### `false` (default):
#### `false`:
```rust
+#[derive(Eq, PartialEq, Debug, Copy, Clone)]
+pub enum Bar {}
+
#[derive(Eq, PartialEq)]
#[derive(Debug)]
#[derive(Copy, Clone)]
How imports should be grouped into `use` statements. Imports will be merged or split to the configured level of granularity.
- **Default value**: `Preserve`
-- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`
+- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One`
- **Stable**: No
#### `Preserve` (default):
use qux::i;
```
+#### `One`:
+
+Merge all imports into a single `use` statement as long as they have the same visibility.
+
+```rust
+pub use foo::{x, y};
+use {
+ bar::{
+ a,
+ b::{self, f, g},
+ c,
+ d::e,
+ },
+ qux::{h, i},
+};
+```
+
## `merge_imports`
This option is deprecated. Use `imports_granularity = "Crate"` instead.
#![doc = "Example documentation"]
#[doc = "Example item documentation"]
+pub enum Bar {}
+
+/// Example item documentation
pub enum Foo {}
```
#### `false`:
```rust
fn main() {
+ (foo());
+
((((foo()))));
}
```
type Item = i32;
}
+
+impl Iterator for Dummy {
+ type Item = i32;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ None
+ }
+}
```
#### `true`
let x = 1;
let y = 2;
let z = 3;
- let a = Foo { x: x, y: y, z: z };
+ let a = Foo { x, y, z };
+ let b = Foo { x: x, y: y, z: z };
}
```
```rust
fn main() {
+ let lorem = ipsum.map(|dolor| dolor.sit())?;
+
let lorem = try!(ipsum.map(|dolor| dolor.sit()));
}
```
#### `false` (default):
```rust
+// Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+// sed do eiusmod tempor incididunt ut labore et dolore
+// magna aliqua. Ut enim ad minim veniam, quis nostrud
+// exercitation ullamco laboris nisi ut aliquip ex ea
+// commodo consequat.
+
// Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
```
-# This is based on https://github.com/japaric/rust-everywhere/blob/master/appveyor.yml
-# and modified (mainly removal of deployment) to suit rustfmt.
-
environment:
global:
PROJECT_NAME: rustfmt
- matrix:
- # Stable channel
- # - TARGET: i686-pc-windows-gnu
- # CHANNEL: stable
- # - TARGET: i686-pc-windows-msvc
- # CHANNEL: stable
- # - TARGET: x86_64-pc-windows-gnu
- # CHANNEL: stable
- # - TARGET: x86_64-pc-windows-msvc
- # CHANNEL: stable
- # Beta channel
- # - TARGET: i686-pc-windows-gnu
- # CHANNEL: beta
- # - TARGET: i686-pc-windows-msvc
- # CHANNEL: beta
- # - TARGET: x86_64-pc-windows-gnu
- # CHANNEL: beta
- # - TARGET: x86_64-pc-windows-msvc
- # CHANNEL: beta
- # Nightly channel
- - TARGET: i686-pc-windows-gnu
- CHANNEL: nightly
- - TARGET: i686-pc-windows-msvc
- CHANNEL: nightly
- - TARGET: x86_64-pc-windows-gnu
- CHANNEL: nightly
- - TARGET: x86_64-pc-windows-msvc
- CHANNEL: nightly
-
-# Install Rust and Cargo
-# (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml)
-install:
- - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- - if "%TARGET%" == "i686-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw32\bin
- - if "%TARGET%" == "x86_64-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw64\bin
- - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
- - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y
- - rustc -Vv
- - cargo -V
-# ???
build: false
test_script:
- - set CFG_RELEASE_CHANNEL=nightly
- - set CFG_RELEASE=nightly
- - cargo build --verbose
- - cargo test
- - cargo test -- --ignored
+ - echo Why does no one have access to delete me?
<html>
<head>
<meta name="viewport" content="width=device-width">
+ <title>Rustfmt</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/3.0.1/github-markdown.css" />
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/styles/github-gist.min.css">
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
+ <script src="https://unpkg.com/vue-async-computed@3.8.1"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.0.0/highlight.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
<style>
@media (max-width: 767px) {
.searchCondition > div {
margin-right: 30px;
}
+ .header-link {
+ position: relative;
+ }
+ .header-link:hover::before {
+ position: absolute;
+ left: -2em;
+ padding-right: 0.5em;
+ content: '\2002\00a7\2002';
+ }
</style>
</head>
<body>
<label for="stable">stable: </label>
<input type="checkbox" id="stable" v-model="shouldStable">
</div>
+ <div>
+ <label for="viewVersion">version: </label>
+ <select name="viewVersion" id="viewVersion" v-model="viewVersion">
+ <option v-for="option in versionOptions" v-bind:value="option">
+ {{ option }}
+ </option>
+ </select>
+ </div>
</div>
<div v-html="aboutHtml"></div>
<div v-html="configurationAboutHtml"></div>
</article>
</div>
<script>
- const ConfigurationMdUrl = 'https://raw.githubusercontent.com/rust-lang/rustfmt/master/Configurations.md';
+ const RusfmtTagsUrl = 'https://api.github.com/repos/rust-lang/rustfmt/tags';
+ const RustfmtLatestUrl = 'https://api.github.com/repos/rust-lang/rustfmt/releases/latest';
const UrlHash = window.location.hash.replace(/^#/, '');
+ const queryParams = new URLSearchParams(window.location.search);
+ const searchParam = queryParams.get('search');
+ const searchTerm = null !== searchParam ? searchParam : '';
+ const versionParam = queryParams.get('version');
+ const parseVersionParam = (version) => {
+ if (version === 'master') return 'master';
+ if (version.startsWith('v')) return version;
+ return `v${version}`;
+ };
+ const versionNumber = null !== versionParam ? parseVersionParam(versionParam) : 'master';
new Vue({
el: '#app',
- data() {
- const configurationDescriptions = [];
- configurationDescriptions.links = {};
- return {
- aboutHtml: '',
- configurationAboutHtml: '',
- searchCondition: UrlHash,
- configurationDescriptions,
- shouldStable: false
- }
+ data: {
+ aboutHtml: '',
+ configurationAboutHtml: '',
+ configurationDescriptions: [],
+ searchCondition: searchTerm,
+ shouldStable: false,
+ viewVersion: versionNumber,
+ oldViewVersion: undefined,
+ versionOptions: ['master'],
+ scrolledOnce: false,
},
- computed: {
- outputHtml() {
- const ast = this.configurationDescriptions
- .filter(({ head, text, stable }) => {
+ asyncComputed: {
+ async updateVersion() {
+ let latest;
+ try {
+ latest = (await axios.get(RustfmtLatestUrl)).data;
+ } catch(err) {
+ console.log(err);
+ return;
+ }
+ if (versionParam == null) {
+ this.viewVersion = latest.name;
+ }
+ },
+ async outputHtml() {
+ if (this.viewVersion !== this.oldViewVersion) {
+ const ConfigurationMdUrl =
+ `https://raw.githubusercontent.com/rust-lang/rustfmt/${this.viewVersion}/Configurations.md`;
+ let res;
+ try {
+ res = await axios.get(ConfigurationMdUrl).catch(e => { throw e });
+ } catch(e) {
+ this.handleReqFailure(e);
+ return;
+ }
+ const {
+ about,
+ configurationAbout,
+ configurationDescriptions
+ } = parseMarkdownAst(res.data);
+ this.aboutHtml = marked.parser(about);
+ this.configurationAboutHtml = marked.parser(configurationAbout);
+ this.configurationDescriptions = configurationDescriptions;
+ this.oldViewVersion = this.viewVersion;
+ }
- if (
- text.includes(this.searchCondition) === false &&
- head.includes(this.searchCondition) === false
- ) {
- return false;
- }
- return (this.shouldStable)
- ? stable === true
- : true;
- })
- .reduce((stack, { value }) => {
- return stack.concat(value);
- }, []);
+ const ast = this.configurationDescriptions
+ .filter(({ head, text, stable }) => {
+ if (text.includes(this.searchCondition) === false &&
+ head.includes(this.searchCondition) === false) {
+ return false;
+ }
+ return (this.shouldStable)
+ ? stable === true
+ : true;
+ })
+ .reduce((stack, { value }) => {
+ return stack.concat(value);
+ }, []);
ast.links = {};
- return marked.parser(ast);
+
+ queryParams.set('version', this.viewVersion);
+ queryParams.set('search', this.searchCondition);
+ const curUrl = window.location.pathname +
+ '?' + queryParams.toString() + window.location.hash;
+ history.pushState(null, '', curUrl);
+
+ const renderer = new marked.Renderer();
+ renderer.heading = function(text, level) {
+ const id = htmlToId(text);
+ return `<h${level}>
+ <a id="${id}" href="#${id}" name="${id}" class="header-link">${text}</a>
+ </h${level}>`;
+ };
+
+ return marked.parser(ast, {
+ highlight(code, lang) {
+ return hljs.highlight(lang ? lang : 'rust', code).value;
+ },
+ headerIds: true,
+ headerPrefix: '',
+ renderer,
+ });
}
},
created: async function() {
- const res = await axios.get(ConfigurationMdUrl);
- const {
- about,
- configurationAbout,
- configurationDescriptions
- } = parseMarkdownAst(res.data);
- this.aboutHtml = marked.parser(about);
- this.configurationAboutHtml = marked.parser(configurationAbout);
- this.configurationDescriptions = configurationDescriptions;
+ let tags;
+ try {
+ tags = (await axios.get(RusfmtTagsUrl)).data;
+ } catch(e) {
+ this.handleReqFailure(e);
+ return;
+ }
+
+ const excludedTagVersions = new Set(['v0.7', 'v0.8.1']);
+
+ const tagOptions = tags
+ .map(tag => tag.name)
+ .filter(tag => tag.startsWith('v') && !excludedTagVersions.has(tag));
+ this.versionOptions = this.versionOptions.concat(tagOptions);
},
- mounted() {
+ updated() {
if (UrlHash === '') return;
- const interval = setInterval(() => {
+ this.$nextTick(() => {
const target = document.querySelector(`#${UrlHash}`);
- if (target != null) {
+ if (target != null && !this.scrolledOnce) {
target.scrollIntoView(true);
- clearInterval(interval);
+ this.scrolledOnce = true;
}
- }, 100);
+ });
+ },
+ methods: {
+ handleReqFailure(e) {
+ if (e.response.status === 404) {
+ this.aboutHtml =
+ "<p>Failed to get configuration options for this version, please select the version from the dropdown above.</p>";
+ } else if (
+ e.response.status === 403 &&
+ e.response.headers["X-RateLimit-Remaining"] === 0
+ ) {
+ const resetDate = new Date(
+ e.response.headers['X-RateLimit-Reset'] * 1000
+ ).toLocaleString();
+ this.aboutHtml =
+ `<p>You have hit the GitHub API rate limit; documentation cannot be updated.` +
+ `<p>The rate limit will be reset at ${resetDate}.</p>`;
+ } else {
+ this.aboutHtml =
+ `<p>Ecountered an error when fetching documentation data:</p>` +
+ `<pre><code>${e.response.data}</code></pre>` +
+ `<p>We would appreciate <a href="https://github.com/rust-lang/rustfmt/issues/new?template=bug_report.md">a bug report</a>.` +
+ `<p>Try refreshing the page.</p>`;
+ }
+ }
}
});
const extractDepthOnes = (ast) => {
head: val[0].text,
value: val,
stable: val.some((elem) => {
- return !!elem.text && elem.text.includes("**Stable**: Yes")
+ return elem.type === "list" &&
+ !!elem.raw &&
+ elem.raw.includes("**Stable**: Yes");
}),
text: val.reduce((result, next) => {
return next.text != null
configurationDescriptions
};
}
+ function htmlToId(text) {
+ const tmpl = document.createElement('template');
+ tmpl.innerHTML = text.trim();
+ return encodeURIComponent(CSS.escape(tmpl.content.textContent));
+ }
</script>
</body>
-</html>
\ No newline at end of file
+</html>
[toolchain]
-channel = "nightly-2021-07-23"
+channel = "nightly-2021-10-20"
components = ["rustc-dev"]
use crate::overflow;
use crate::rewrite::{Rewrite, RewriteContext};
use crate::shape::Shape;
+use crate::source_map::SpanUtils;
use crate::types::{rewrite_path, PathContext};
use crate::utils::{count_newlines, mk_sp};
|span| span.lo(),
|span| span.hi(),
|span| Some(context.snippet(*span).to_owned()),
- attr.span.lo(),
+ // We update derive attribute spans to start after the opening '('
+ // This helps us focus parsing to just what's inside #[derive(...)]
+ context.snippet_provider.span_after(attr.span, "("),
attr.span.hi(),
false,
);
found reverts to the input file path",
"[Path for the configuration file]",
);
- opts.optopt("", "edition", "Rust edition to use", "[2015|2018]");
+ opts.optopt("", "edition", "Rust edition to use", "[2015|2018|2021]");
opts.optopt(
"",
"color",
use structopt::StructOpt;
+#[path = "test/mod.rs"]
+#[cfg(test)]
+mod cargo_fmt_tests;
+
#[derive(StructOpt, Debug)]
#[structopt(
bin_name = "cargo fmt",
#[structopt(long = "version")]
version: bool,
- /// Specify package to format (only usable in workspaces)
+ /// Specify package to format
#[structopt(short = "p", long = "package", value_name = "package")]
packages: Vec<String>,
#[structopt(name = "rustfmt_options", raw(true))]
rustfmt_options: Vec<String>,
- /// Format all packages (only usable in workspaces)
+ /// Format all packages, and also their local path-based dependencies
#[structopt(long = "all")]
format_all: bool,
+
+ /// Run rustfmt in check mode
+ #[structopt(long = "check")]
+ check: bool,
}
fn main() {
let strategy = CargoFmtStrategy::from_opts(&opts);
let mut rustfmt_args = opts.rustfmt_options;
+ if opts.check {
+ let check_flag = "--check";
+ if !rustfmt_args.iter().any(|o| o == check_flag) {
+ rustfmt_args.push(check_flag.to_owned());
+ }
+ }
if let Some(message_format) = opts.message_format {
if let Err(msg) = convert_message_format_to_rustfmt_args(&message_format, &mut rustfmt_args)
{
manifest_path: Option<&Path>,
targets: &mut BTreeSet<Target>,
) -> Result<(), io::Error> {
- let metadata = get_cargo_metadata(manifest_path, false)?;
+ let metadata = get_cargo_metadata(manifest_path)?;
let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?;
let (in_workspace_root, current_dir_manifest) = if let Some(target_manifest) = manifest_path {
(
mut targets: &mut BTreeSet<Target>,
visited: &mut BTreeSet<String>,
) -> Result<(), io::Error> {
- let metadata = get_cargo_metadata(manifest_path, false)?;
- let metadata_with_deps = get_cargo_metadata(manifest_path, true)?;
-
- for package in metadata.packages {
+ let metadata = get_cargo_metadata(manifest_path)?;
+ for package in &metadata.packages {
add_targets(&package.targets, &mut targets);
- // Look for local dependencies.
- for dependency in package.dependencies {
- if dependency.source.is_some() || visited.contains(&dependency.name) {
+ // Look for local dependencies using information available since cargo v1.51
+ // It's theoretically possible someone could use a newer version of rustfmt with
+ // a much older version of `cargo`, but we don't try to explicitly support that scenario.
+ // If someone reports an issue with path-based deps not being formatted, be sure to
+ // confirm their version of `cargo` (not `cargo-fmt`) is >= v1.51
+ // https://github.com/rust-lang/cargo/pull/8994
+ for dependency in &package.dependencies {
+ if dependency.path.is_none() || visited.contains(&dependency.name) {
continue;
}
- let dependency_package = metadata_with_deps
- .packages
- .iter()
- .find(|p| p.name == dependency.name && p.source.is_none());
- let manifest_path = if let Some(dep_pkg) = dependency_package {
- PathBuf::from(&dep_pkg.manifest_path)
- } else {
- let mut package_manifest_path = PathBuf::from(&package.manifest_path);
- package_manifest_path.pop();
- package_manifest_path.push(&dependency.name);
- package_manifest_path.push("Cargo.toml");
- package_manifest_path
- };
-
- if manifest_path.exists() {
- visited.insert(dependency.name);
+ let manifest_path = PathBuf::from(dependency.path.as_ref().unwrap()).join("Cargo.toml");
+ if manifest_path.exists()
+ && !metadata
+ .packages
+ .iter()
+ .any(|p| p.manifest_path.eq(&manifest_path))
+ {
+ visited.insert(dependency.name.to_owned());
get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
}
}
hitlist: &[String],
targets: &mut BTreeSet<Target>,
) -> Result<(), io::Error> {
- let metadata = get_cargo_metadata(manifest_path, false)?;
-
+ let metadata = get_cargo_metadata(manifest_path)?;
let mut workspace_hitlist: BTreeSet<&String> = BTreeSet::from_iter(hitlist);
for package in metadata.packages {
.unwrap_or(SUCCESS))
}
-fn get_cargo_metadata(
- manifest_path: Option<&Path>,
- include_deps: bool,
-) -> Result<cargo_metadata::Metadata, io::Error> {
+fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
let mut cmd = cargo_metadata::MetadataCommand::new();
- if !include_deps {
- cmd.no_deps();
- }
+ cmd.no_deps();
if let Some(manifest_path) = manifest_path {
cmd.manifest_path(manifest_path);
}
- cmd.other_options(&[String::from("--offline")]);
+ cmd.other_options(vec![String::from("--offline")]);
match cmd.exec() {
Ok(metadata) => Ok(metadata),
}
}
}
-
-#[cfg(test)]
-mod cargo_fmt_tests {
- use super::*;
-
- #[test]
- fn default_options() {
- let empty: Vec<String> = vec![];
- let o = Opts::from_iter(&empty);
- assert_eq!(false, o.quiet);
- assert_eq!(false, o.verbose);
- assert_eq!(false, o.version);
- assert_eq!(empty, o.packages);
- assert_eq!(empty, o.rustfmt_options);
- assert_eq!(false, o.format_all);
- assert_eq!(None, o.manifest_path);
- assert_eq!(None, o.message_format);
- }
-
- #[test]
- fn good_options() {
- let o = Opts::from_iter(&[
- "test",
- "-q",
- "-p",
- "p1",
- "-p",
- "p2",
- "--message-format",
- "short",
- "--",
- "--edition",
- "2018",
- ]);
- assert_eq!(true, o.quiet);
- assert_eq!(false, o.verbose);
- assert_eq!(false, o.version);
- assert_eq!(vec!["p1", "p2"], o.packages);
- assert_eq!(vec!["--edition", "2018"], o.rustfmt_options);
- assert_eq!(false, o.format_all);
- assert_eq!(Some(String::from("short")), o.message_format);
- }
-
- #[test]
- fn unexpected_option() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "unexpected"])
- .is_err()
- );
- }
-
- #[test]
- fn unexpected_flag() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "--flag"])
- .is_err()
- );
- }
-
- #[test]
- fn mandatory_separator() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "--check"])
- .is_err()
- );
- assert!(
- !Opts::clap()
- .get_matches_from_safe(&["test", "--", "--check"])
- .is_err()
- );
- }
-
- #[test]
- fn multiple_packages_one_by_one() {
- let o = Opts::from_iter(&[
- "test",
- "-p",
- "package1",
- "--package",
- "package2",
- "-p",
- "package3",
- ]);
- assert_eq!(3, o.packages.len());
- }
-
- #[test]
- fn multiple_packages_grouped() {
- let o = Opts::from_iter(&[
- "test",
- "--package",
- "package1",
- "package2",
- "-p",
- "package3",
- "package4",
- ]);
- assert_eq!(4, o.packages.len());
- }
-
- #[test]
- fn empty_packages_1() {
- assert!(Opts::clap().get_matches_from_safe(&["test", "-p"]).is_err());
- }
-
- #[test]
- fn empty_packages_2() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "-p", "--", "--check"])
- .is_err()
- );
- }
-
- #[test]
- fn empty_packages_3() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "-p", "--verbose"])
- .is_err()
- );
- }
-
- #[test]
- fn empty_packages_4() {
- assert!(
- Opts::clap()
- .get_matches_from_safe(&["test", "-p", "--check"])
- .is_err()
- );
- }
-
- mod convert_message_format_to_rustfmt_args_tests {
- use super::*;
-
- #[test]
- fn invalid_message_format() {
- assert_eq!(
- convert_message_format_to_rustfmt_args("awesome", &mut vec![]),
- Err(String::from(
- "invalid --message-format value: awesome. Allowed values are: short|json|human"
- )),
- );
- }
-
- #[test]
- fn json_message_format_and_check_arg() {
- let mut args = vec![String::from("--check")];
- assert_eq!(
- convert_message_format_to_rustfmt_args("json", &mut args),
- Err(String::from(
- "cannot include --check arg when --message-format is set to json"
- )),
- );
- }
-
- #[test]
- fn json_message_format_and_emit_arg() {
- let mut args = vec![String::from("--emit"), String::from("checkstyle")];
- assert_eq!(
- convert_message_format_to_rustfmt_args("json", &mut args),
- Err(String::from(
- "cannot include --emit arg when --message-format is set to json"
- )),
- );
- }
-
- #[test]
- fn json_message_format() {
- let mut args = vec![String::from("--edition"), String::from("2018")];
- assert!(convert_message_format_to_rustfmt_args("json", &mut args).is_ok());
- assert_eq!(
- args,
- vec![
- String::from("--edition"),
- String::from("2018"),
- String::from("--emit"),
- String::from("json")
- ]
- );
- }
-
- #[test]
- fn human_message_format() {
- let exp_args = vec![String::from("--emit"), String::from("json")];
- let mut act_args = exp_args.clone();
- assert!(convert_message_format_to_rustfmt_args("human", &mut act_args).is_ok());
- assert_eq!(act_args, exp_args);
- }
-
- #[test]
- fn short_message_format() {
- let mut args = vec![String::from("--check")];
- assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
- assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
- }
-
- #[test]
- fn short_message_format_included_short_list_files_flag() {
- let mut args = vec![String::from("--check"), String::from("-l")];
- assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
- assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
- }
-
- #[test]
- fn short_message_format_included_long_list_files_flag() {
- let mut args = vec![String::from("--check"), String::from("--files-with-diff")];
- assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
- assert_eq!(
- args,
- vec![String::from("--check"), String::from("--files-with-diff")]
- );
- }
- }
-}
--- /dev/null
+use super::*;
+
+#[test]
+fn invalid_message_format() {
+ assert_eq!(
+ convert_message_format_to_rustfmt_args("awesome", &mut vec![]),
+ Err(String::from(
+ "invalid --message-format value: awesome. Allowed values are: short|json|human"
+ )),
+ );
+}
+
+#[test]
+fn json_message_format_and_check_arg() {
+ let mut args = vec![String::from("--check")];
+ assert_eq!(
+ convert_message_format_to_rustfmt_args("json", &mut args),
+ Err(String::from(
+ "cannot include --check arg when --message-format is set to json"
+ )),
+ );
+}
+
+#[test]
+fn json_message_format_and_emit_arg() {
+ let mut args = vec![String::from("--emit"), String::from("checkstyle")];
+ assert_eq!(
+ convert_message_format_to_rustfmt_args("json", &mut args),
+ Err(String::from(
+ "cannot include --emit arg when --message-format is set to json"
+ )),
+ );
+}
+
+#[test]
+fn json_message_format() {
+ let mut args = vec![String::from("--edition"), String::from("2018")];
+ assert!(convert_message_format_to_rustfmt_args("json", &mut args).is_ok());
+ assert_eq!(
+ args,
+ vec![
+ String::from("--edition"),
+ String::from("2018"),
+ String::from("--emit"),
+ String::from("json")
+ ]
+ );
+}
+
+#[test]
+fn human_message_format() {
+ let exp_args = vec![String::from("--emit"), String::from("json")];
+ let mut act_args = exp_args.clone();
+ assert!(convert_message_format_to_rustfmt_args("human", &mut act_args).is_ok());
+ assert_eq!(act_args, exp_args);
+}
+
+#[test]
+fn short_message_format() {
+ let mut args = vec![String::from("--check")];
+ assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
+ assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
+}
+
+#[test]
+fn short_message_format_included_short_list_files_flag() {
+ let mut args = vec![String::from("--check"), String::from("-l")];
+ assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
+ assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
+}
+
+#[test]
+fn short_message_format_included_long_list_files_flag() {
+ let mut args = vec![String::from("--check"), String::from("--files-with-diff")];
+ assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
+ assert_eq!(
+ args,
+ vec![String::from("--check"), String::from("--files-with-diff")]
+ );
+}
--- /dev/null
+use super::*;
+
+mod message_format;
+mod targets;
+
+#[test]
+fn default_options() {
+ let empty: Vec<String> = vec![];
+ let o = Opts::from_iter(&empty);
+ assert_eq!(false, o.quiet);
+ assert_eq!(false, o.verbose);
+ assert_eq!(false, o.version);
+ assert_eq!(false, o.check);
+ assert_eq!(empty, o.packages);
+ assert_eq!(empty, o.rustfmt_options);
+ assert_eq!(false, o.format_all);
+ assert_eq!(None, o.manifest_path);
+ assert_eq!(None, o.message_format);
+}
+
+#[test]
+fn good_options() {
+ let o = Opts::from_iter(&[
+ "test",
+ "-q",
+ "-p",
+ "p1",
+ "-p",
+ "p2",
+ "--message-format",
+ "short",
+ "--check",
+ "--",
+ "--edition",
+ "2018",
+ ]);
+ assert_eq!(true, o.quiet);
+ assert_eq!(false, o.verbose);
+ assert_eq!(false, o.version);
+ assert_eq!(true, o.check);
+ assert_eq!(vec!["p1", "p2"], o.packages);
+ assert_eq!(vec!["--edition", "2018"], o.rustfmt_options);
+ assert_eq!(false, o.format_all);
+ assert_eq!(Some(String::from("short")), o.message_format);
+}
+
+#[test]
+fn unexpected_option() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "unexpected"])
+ .is_err()
+ );
+}
+
+#[test]
+fn unexpected_flag() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "--flag"])
+ .is_err()
+ );
+}
+
+#[test]
+fn mandatory_separator() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "--emit"])
+ .is_err()
+ );
+ assert!(
+ !Opts::clap()
+ .get_matches_from_safe(&["test", "--", "--emit"])
+ .is_err()
+ );
+}
+
+#[test]
+fn multiple_packages_one_by_one() {
+ let o = Opts::from_iter(&[
+ "test",
+ "-p",
+ "package1",
+ "--package",
+ "package2",
+ "-p",
+ "package3",
+ ]);
+ assert_eq!(3, o.packages.len());
+}
+
+#[test]
+fn multiple_packages_grouped() {
+ let o = Opts::from_iter(&[
+ "test",
+ "--package",
+ "package1",
+ "package2",
+ "-p",
+ "package3",
+ "package4",
+ ]);
+ assert_eq!(4, o.packages.len());
+}
+
+#[test]
+fn empty_packages_1() {
+ assert!(Opts::clap().get_matches_from_safe(&["test", "-p"]).is_err());
+}
+
+#[test]
+fn empty_packages_2() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "-p", "--", "--check"])
+ .is_err()
+ );
+}
+
+#[test]
+fn empty_packages_3() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "-p", "--verbose"])
+ .is_err()
+ );
+}
+
+#[test]
+fn empty_packages_4() {
+ assert!(
+ Opts::clap()
+ .get_matches_from_safe(&["test", "-p", "--check"])
+ .is_err()
+ );
+}
--- /dev/null
+use super::*;
+
+struct ExpTarget {
+ path: &'static str,
+ edition: &'static str,
+ kind: &'static str,
+}
+
+mod all_targets {
+ use super::*;
+
+ fn assert_correct_targets_loaded(
+ manifest_suffix: &str,
+ source_root: &str,
+ exp_targets: &[ExpTarget],
+ exp_num_targets: usize,
+ ) {
+ let root_path = Path::new("tests/cargo-fmt/source").join(source_root);
+ let get_path = |exp: &str| PathBuf::from(&root_path).join(exp).canonicalize().unwrap();
+ let manifest_path = Path::new(&root_path).join(manifest_suffix);
+ let targets = get_targets(&CargoFmtStrategy::All, Some(manifest_path.as_path()))
+ .expect("Targets should have been loaded");
+
+ assert_eq!(targets.len(), exp_num_targets);
+
+ for target in exp_targets {
+ assert!(targets.contains(&Target {
+ path: get_path(target.path),
+ edition: target.edition.to_owned(),
+ kind: target.kind.to_owned(),
+ }));
+ }
+ }
+
+ mod different_crate_and_dir_names {
+ use super::*;
+
+ fn assert_correct_targets_loaded(manifest_suffix: &str) {
+ let exp_targets = vec![
+ ExpTarget {
+ path: "dependency-dir-name/subdep-dir-name/src/lib.rs",
+ edition: "2018",
+ kind: "lib",
+ },
+ ExpTarget {
+ path: "dependency-dir-name/src/lib.rs",
+ edition: "2018",
+ kind: "lib",
+ },
+ ExpTarget {
+ path: "src/main.rs",
+ edition: "2018",
+ kind: "main",
+ },
+ ];
+ super::assert_correct_targets_loaded(
+ manifest_suffix,
+ "divergent-crate-dir-names",
+ &exp_targets,
+ 3,
+ );
+ }
+
+ #[test]
+ fn correct_targets_from_root() {
+ assert_correct_targets_loaded("Cargo.toml");
+ }
+
+ #[test]
+ fn correct_targets_from_sub_local_dep() {
+ assert_correct_targets_loaded("dependency-dir-name/Cargo.toml");
+ }
+ }
+
+ mod workspaces {
+ use super::*;
+
+ fn assert_correct_targets_loaded(manifest_suffix: &str) {
+ let exp_targets = vec![
+ ExpTarget {
+ path: "ws/a/src/main.rs",
+ edition: "2018",
+ kind: "bin",
+ },
+ ExpTarget {
+ path: "ws/b/src/main.rs",
+ edition: "2018",
+ kind: "bin",
+ },
+ ExpTarget {
+ path: "ws/c/src/lib.rs",
+ edition: "2018",
+ kind: "lib",
+ },
+ ExpTarget {
+ path: "ws/a/d/src/lib.rs",
+ edition: "2018",
+ kind: "lib",
+ },
+ ExpTarget {
+ path: "e/src/main.rs",
+ edition: "2018",
+ kind: "main",
+ },
+ ExpTarget {
+ path: "ws/a/d/f/src/lib.rs",
+ edition: "2018",
+ kind: "lib",
+ },
+ ];
+ super::assert_correct_targets_loaded(
+ manifest_suffix,
+ "workspaces/path-dep-above",
+ &exp_targets,
+ 6,
+ );
+ }
+
+ #[test]
+ fn includes_outside_workspace_deps() {
+ assert_correct_targets_loaded("ws/Cargo.toml");
+ }
+
+ #[test]
+ fn includes_workspace_from_dep_above() {
+ assert_correct_targets_loaded("e/Cargo.toml");
+ }
+
+ #[test]
+ fn includes_all_packages_from_workspace_subdir() {
+ assert_correct_targets_loaded("ws/a/d/f/Cargo.toml");
+ }
+ }
+}
use crate::shape::{Indent, Shape};
use crate::string::{rewrite_string, StringFormat};
use crate::utils::{
- count_newlines, first_line_width, last_line_width, trim_left_preserve_layout, unicode_str_width,
+ count_newlines, first_line_width, last_line_width, trim_left_preserve_layout,
+ trimmed_last_line_width, unicode_str_width,
};
use crate::{ErrorKind, FormattingError};
String::with_capacity(prev_str.len() + next_str.len() + shape.indent.width() + 128);
result.push_str(prev_str);
let mut allow_one_line = !prev_str.contains('\n') && !next_str.contains('\n');
- let first_sep = if prev_str.is_empty() || next_str.is_empty() {
- ""
- } else {
- " "
- };
+ let first_sep =
+ if prev_str.is_empty() || next_str.is_empty() || trimmed_last_line_width(prev_str) == 0 {
+ ""
+ } else {
+ " "
+ };
let mut one_line_width =
last_line_width(prev_str) + first_line_width(next_str) + first_sep.len();
let missing_comment = rewrite_missing_comment(span, shape, context)?;
if missing_comment.is_empty() {
- if allow_extend && prev_str.len() + first_sep.len() + next_str.len() <= shape.width {
+ if allow_extend && one_line_width <= shape.width {
result.push_str(first_sep);
} else if !prev_str.is_empty() {
result.push_str(&indent.to_string_with_newline(config))
}
}
-/// Attributes for code blocks in rustdoc.
-/// See <https://doc.rust-lang.org/rustdoc/print.html#attributes>.
+/// Enum indicating if the code block contains rust based on attributes
enum CodeBlockAttribute {
Rust,
- Ignore,
- Text,
- ShouldPanic,
- NoRun,
- CompileFail,
+ NotRust,
}
impl CodeBlockAttribute {
- fn new(attribute: &str) -> CodeBlockAttribute {
- match attribute {
- "rust" | "" => CodeBlockAttribute::Rust,
- "ignore" => CodeBlockAttribute::Ignore,
- "text" => CodeBlockAttribute::Text,
- "should_panic" => CodeBlockAttribute::ShouldPanic,
- "no_run" => CodeBlockAttribute::NoRun,
- "compile_fail" => CodeBlockAttribute::CompileFail,
- _ => CodeBlockAttribute::Text,
+ /// Parse comma separated attributes list. Return rust only if all
+ /// 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(",") {
+ match attribute.trim() {
+ "" | "rust" | "should_panic" | "no_run" | "edition2015" | "edition2018"
+ | "edition2021" => (),
+ "ignore" | "compile_fail" | "text" => return CodeBlockAttribute::NotRust,
+ _ => return CodeBlockAttribute::NotRust,
+ }
}
+ CodeBlockAttribute::Rust
}
}
} else if self.code_block_attr.is_some() {
if line.starts_with("```") {
let code_block = match self.code_block_attr.as_ref().unwrap() {
- CodeBlockAttribute::Ignore | CodeBlockAttribute::Text => {
- trim_custom_comment_prefix(&self.code_block_buffer)
- }
- _ if self.code_block_buffer.is_empty() => String::new(),
- _ => {
+ CodeBlockAttribute::Rust
+ if self.fmt.config.format_code_in_doc_comments()
+ && !self.code_block_buffer.is_empty() =>
+ {
let mut config = self.fmt.config.clone();
config.set().wrap_comments(false);
- if config.format_code_in_doc_comments() {
- if let Some(s) =
- crate::format_code_block(&self.code_block_buffer, &config, false)
- {
- trim_custom_comment_prefix(&s.snippet)
- } else {
- trim_custom_comment_prefix(&self.code_block_buffer)
- }
+ if let Some(s) =
+ crate::format_code_block(&self.code_block_buffer, &config, false)
+ {
+ trim_custom_comment_prefix(&s.snippet)
} else {
trim_custom_comment_prefix(&self.code_block_buffer)
}
}
+ _ => trim_custom_comment_prefix(&self.code_block_buffer),
};
if !code_block.is_empty() {
self.result.push_str(&self.comment_line_separator);
format_macro_matchers: bool, false, false,
"Format the metavariable matching patterns in macros";
format_macro_bodies: bool, true, false, "Format the bodies of macros";
+ hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false,
+ "Format hexadecimal integer literals";
// Single line expressions and items
empty_item_single_line: bool, true, false,
"Add trailing semicolon after break, continue and return";
trailing_comma: SeparatorTactic, SeparatorTactic::Vertical, false,
"How to handle trailing commas for lists";
- match_block_trailing_comma: bool, false, false,
+ match_block_trailing_comma: bool, false, true,
"Put a trailing comma after a block based match arm (non-block arms are not affected)";
blank_lines_upper_bound: usize, 1, false,
"Maximum number of blank lines which can be put between items";
inline_attribute_width: usize, 0, false,
"Write an item and its attribute on the same line \
if their combined width is below a threshold";
+ format_generated_files: bool, false, false, "Format generated files";
// Options that can change the source code beyond whitespace/blocks (somewhat linty things)
merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
"Require a specific version of rustfmt";
unstable_features: bool, false, false,
"Enables unstable features. Only available on nightly channel";
- disable_all_formatting: bool, false, false, "Don't reformat anything";
+ disable_all_formatting: bool, false, true, "Don't reformat anything";
skip_children: bool, false, false, "Don't reformat out of line modules";
hide_parse_errors: bool, false, false, "Hide errors from the parser";
error_on_line_overflow: bool, false, false, "Error if unable to get all lines within max_width";
format_strings = false
format_macro_matchers = false
format_macro_bodies = true
+hex_literal_case = "Preserve"
empty_item_single_line = true
struct_lit_single_line = true
fn_single_line = false
edition = "2015"
version = "One"
inline_attribute_width = 0
+format_generated_files = false
merge_derives = true
use_try_shorthand = false
use_field_init_shorthand = false
Module,
/// Use one `use` statement per imported item.
Item,
+ /// Use one `use` statement including all items.
+ One,
+}
+
+/// Controls how rustfmt should handle case in hexadecimal literals.
+#[config_type]
+pub enum HexLiteralCase {
+ /// Leave the literal as-is
+ Preserve,
+ /// Ensure all literals use uppercase lettering
+ Upper,
+ /// Ensure all literals use lowercase lettering
+ Lower,
}
#[config_type]
rewrite_missing_comment, CharClasses, FindUncommented,
};
use crate::config::lists::*;
-use crate::config::{Config, ControlBraceStyle, IndentStyle, Version};
+use crate::config::{Config, ControlBraceStyle, HexLiteralCase, IndentStyle, Version};
use crate::lists::{
definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape,
struct_lit_tactic, write_list, ListFormatting, Separator,
let pat_string = pat.rewrite(context, pat_shape)?;
let comments_lo = context
.snippet_provider
- .span_after(self.span, self.connector.trim());
+ .span_after(self.span.with_lo(pat.span.hi()), self.connector.trim());
let comments_span = mk_sp(comments_lo, expr.span.lo());
return rewrite_assign_rhs_with_comments(
context,
) -> Option<String> {
match l.kind {
ast::LitKind::Str(_, ast::StrStyle::Cooked) => rewrite_string_lit(context, l.span, shape),
+ ast::LitKind::Int(..) => rewrite_int_lit(context, l, shape),
_ => wrap_str(
context.snippet(l.span).to_owned(),
context.config.max_width(),
)
}
+fn rewrite_int_lit(context: &RewriteContext<'_>, lit: &ast::Lit, shape: Shape) -> Option<String> {
+ let span = lit.span;
+ let symbol = lit.token.symbol.as_str();
+
+ if symbol.starts_with("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()),
+ };
+ if let Some(hex_lit) = hex_lit {
+ return wrap_str(
+ format!(
+ "0x{}{}",
+ hex_lit,
+ lit.token.suffix.map_or(String::new(), |s| s.to_string())
+ ),
+ context.config.max_width(),
+ shape,
+ );
+ }
+ }
+
+ wrap_str(
+ context.snippet(span).to_owned(),
+ context.config.max_width(),
+ shape,
+ )
+}
+
fn choose_separator_tactic(context: &RewriteContext<'_>, span: Span) -> Option<SeparatorTactic> {
if context.inside_macro() {
if span_ends_with_comma(context, span) {
let path_shape = shape.sub_width(2)?;
let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
- let has_base = match struct_rest {
+ let has_base_or_rest = match struct_rest {
ast::StructRest::None if fields.is_empty() => return Some(format!("{} {{}}", path_str)),
ast::StructRest::Rest(_) if fields.is_empty() => {
return Some(format!("{} {{ .. }}", path_str));
}
- ast::StructRest::Base(_) => true,
+ ast::StructRest::Rest(_) | ast::StructRest::Base(_) => true,
_ => false,
};
let one_line_width = h_shape.map_or(0, |shape| shape.width);
let body_lo = context.snippet_provider.span_after(span, "{");
- let fields_str = if struct_lit_can_be_aligned(fields, has_base)
+ let fields_str = if struct_lit_can_be_aligned(fields, has_base_or_rest)
&& context.config.struct_field_align_threshold() > 0
{
rewrite_with_alignment(
nested_shape,
tactic,
context,
- force_no_trailing_comma
- || has_base
- || !context.use_block_indent()
- || matches!(struct_rest, ast::StructRest::Rest(_)),
+ force_no_trailing_comma || has_base_or_rest || !context.use_block_indent(),
);
write_list(&item_vec, &fmt)?
use self::newline_style::apply_newline_style;
use crate::comment::{CharClasses, FullCodeCharKind};
use crate::config::{Config, FileName, Verbosity};
+use crate::formatting::generated::is_generated_file;
use crate::issues::BadIssueSeeker;
use crate::modules::Module;
use crate::syntux::parser::{DirectoryOwnership, Parser, ParserError};
use crate::visitor::FmtVisitor;
use crate::{modules, source_file, ErrorKind, FormatReport, Input, Session};
+mod generated;
mod newline_style;
// A map of the files of a crate, with their new content
context.parse_session.set_silent_emitter();
for (path, module) in files {
- let should_ignore = !input_is_stdin && context.ignore_file(&path);
+ let source_file = context.parse_session.span_to_file_contents(module.span);
+ let src = source_file.src.as_ref().expect("SourceFile without src");
+
+ let should_ignore = (!input_is_stdin && context.ignore_file(&path))
+ || (!config.format_generated_files() && is_generated_file(src));
+
if (config.skip_children() && path != main_file) || should_ignore {
continue;
}
--- /dev/null
+/// Returns `true` if the given span is a part of generated files.
+pub(super) fn is_generated_file(original_snippet: &str) -> bool {
+ original_snippet
+ .lines()
+ .take(5) // looking for marker only in the beginning of the file
+ .any(|line| line.contains("@generated"))
+}
}
}
+ // Check if self == other with their aliases removed.
+ fn equal_except_alias(&self, other: &Self) -> bool {
+ match (self, other) {
+ (UseSegment::Ident(ref s1, _), UseSegment::Ident(ref s2, _)) => s1 == s2,
+ (UseSegment::Slf(_), UseSegment::Slf(_))
+ | (UseSegment::Super(_), UseSegment::Super(_))
+ | (UseSegment::Crate(_), UseSegment::Crate(_))
+ | (UseSegment::Glob, UseSegment::Glob) => true,
+ (UseSegment::List(ref list1), UseSegment::List(ref list2)) => list1 == list2,
+ _ => false,
+ }
+ }
+
+ fn get_alias(&self) -> Option<&str> {
+ match self {
+ UseSegment::Ident(_, a)
+ | UseSegment::Slf(a)
+ | UseSegment::Super(a)
+ | UseSegment::Crate(a) => a.as_deref(),
+ _ => None,
+ }
+ }
+
fn from_path_segment(
context: &RewriteContext<'_>,
path_seg: &ast::PathSegment,
SharedPrefix::Module => {
self.path[..self.path.len() - 1] == other.path[..other.path.len() - 1]
}
+ SharedPrefix::One => true,
}
}
}
fn merge(&mut self, other: &UseTree, merge_by: SharedPrefix) {
let mut prefix = 0;
for (a, b) in self.path.iter().zip(other.path.iter()) {
- if *a == *b {
+ if a.equal_except_alias(b) {
prefix += 1;
} else {
break;
return Some(new_path);
}
} else if len == 1 {
- let rest = if a.len() == len { &b[1..] } else { &a[1..] };
- return Some(vec![
- b[0].clone(),
- UseSegment::List(vec![
- UseTree::from_path(vec![UseSegment::Slf(None)], DUMMY_SP),
- UseTree::from_path(rest.to_vec(), DUMMY_SP),
- ]),
- ]);
+ let (common, rest) = if a.len() == len {
+ (&a[0], &b[1..])
+ } else {
+ (&b[0], &a[1..])
+ };
+ let mut list = vec![UseTree::from_path(
+ vec![UseSegment::Slf(common.get_alias().map(ToString::to_string))],
+ DUMMY_SP,
+ )];
+ match rest {
+ [UseSegment::List(rest_list)] => list.extend(rest_list.clone()),
+ _ => list.push(UseTree::from_path(rest.to_vec(), DUMMY_SP)),
+ }
+ return Some(vec![b[0].clone(), UseSegment::List(list)]);
} else {
len -= 1;
}
}
fn merge_use_trees_inner(trees: &mut Vec<UseTree>, use_tree: UseTree, merge_by: SharedPrefix) {
- let similar_trees = trees
- .iter_mut()
- .filter(|tree| tree.share_prefix(&use_tree, merge_by));
+ struct SimilarTree<'a> {
+ similarity: usize,
+ path_len: usize,
+ tree: &'a mut UseTree,
+ }
+
+ let similar_trees = trees.iter_mut().filter_map(|tree| {
+ if tree.share_prefix(&use_tree, merge_by) {
+ // In the case of `SharedPrefix::One`, `similarity` is used for deciding with which
+ // tree `use_tree` should be merge.
+ // In other cases `similarity` won't be used, so set it to `0` as a dummy value.
+ let similarity = if merge_by == SharedPrefix::One {
+ tree.path
+ .iter()
+ .zip(&use_tree.path)
+ .take_while(|(a, b)| a.equal_except_alias(b))
+ .count()
+ } else {
+ 0
+ };
+
+ let path_len = tree.path.len();
+ Some(SimilarTree {
+ similarity,
+ tree,
+ path_len,
+ })
+ } else {
+ None
+ }
+ });
+
if use_tree.path.len() == 1 && merge_by == SharedPrefix::Crate {
- if let Some(tree) = similar_trees.min_by_key(|tree| tree.path.len()) {
- if tree.path.len() == 1 {
+ if let Some(tree) = similar_trees.min_by_key(|tree| tree.path_len) {
+ if tree.path_len == 1 {
+ return;
+ }
+ }
+ } else if merge_by == SharedPrefix::One {
+ if let Some(sim_tree) = similar_trees.max_by_key(|tree| tree.similarity) {
+ if sim_tree.similarity > 0 {
+ sim_tree.tree.merge(&use_tree, merge_by);
return;
}
}
- } else if let Some(tree) = similar_trees.max_by_key(|tree| tree.path.len()) {
- if tree.path.len() > 1 {
- tree.merge(&use_tree, merge_by);
+ } else if let Some(sim_tree) = similar_trees.max_by_key(|tree| tree.path_len) {
+ if sim_tree.path_len > 1 {
+ sim_tree.tree.merge(&use_tree, merge_by);
return;
}
}
pub(crate) enum SharedPrefix {
Crate,
Module,
+ One,
}
#[cfg(test)]
}
fn eat(&mut self, c: char) {
- assert!(self.input.next().unwrap() == c);
+ assert_eq!(self.input.next().unwrap(), c);
}
fn push_segment(
);
}
+ #[test]
+ fn test_use_tree_merge_one() {
+ test_merge!(One, ["a", "b"], ["{a, b}"]);
+
+ test_merge!(One, ["a::{aa, ab}", "b", "a"], ["{a::{self, aa, ab}, b}"]);
+
+ test_merge!(One, ["a as x", "b as y"], ["{a as x, b as y}"]);
+
+ test_merge!(
+ One,
+ ["a::{aa as xa, ab}", "b", "a"],
+ ["{a::{self, aa as xa, ab}, b}"]
+ );
+
+ test_merge!(
+ One,
+ ["a", "a::{aa, ab::{aba, abb}}"],
+ ["a::{self, aa, ab::{aba, abb}}"]
+ );
+
+ test_merge!(One, ["a", "b::{ba, *}"], ["{a, b::{ba, *}}"]);
+
+ test_merge!(One, ["a", "b", "a::aa"], ["{a::{self, aa}, b}"]);
+
+ test_merge!(
+ One,
+ ["a::aa::aaa", "a::ac::aca", "a::aa::*"],
+ ["a::{aa::{aaa, *}, ac::aca}"]
+ );
+
+ test_merge!(
+ One,
+ ["a", "b::{ba, bb}", "a::{aa::*, ab::aba}"],
+ ["{a::{self, aa::*, ab::aba}, b::{ba, bb}}"]
+ );
+
+ test_merge!(
+ One,
+ ["b", "a::ac::{aca, acb}", "a::{aa::*, ab}"],
+ ["{a::{aa::*, ab, ac::{aca, acb}}, b}"]
+ );
+ }
+
#[test]
fn test_flatten_use_trees() {
assert_eq!(
constness: ast::Const,
defaultness: ast::Defaultness,
unsafety: ast::Unsafe,
- visibility: ast::Visibility,
+ visibility: &'a ast::Visibility,
}
impl<'a> FnSig<'a> {
pub(crate) fn from_method_sig(
method_sig: &'a ast::FnSig,
generics: &'a ast::Generics,
- visibility: ast::Visibility,
+ visibility: &'a ast::Visibility,
) -> FnSig<'a> {
FnSig {
unsafety: method_sig.header.unsafety,
match *fn_kind {
visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, _) => match fn_ctxt {
visit::FnCtxt::Assoc(..) => {
- let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis.clone());
+ let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
fn_sig.defaultness = defaultness;
fn_sig
}
is_async: Cow::Borrowed(&fn_sig.header.asyncness),
defaultness,
unsafety: fn_sig.header.unsafety,
- visibility: vis.clone(),
+ visibility: vis,
},
},
_ => unreachable!(),
indent: Indent,
ident: symbol::Ident,
sig: &ast::FnSig,
+ vis: &ast::Visibility,
generics: &ast::Generics,
span: Span,
) -> Option<String> {
&context,
indent,
ident,
- &FnSig::from_method_sig(sig, generics, DEFAULT_VISIBILITY),
+ &FnSig::from_method_sig(sig, generics, vis),
span,
FnBraceStyle::None,
)?;
format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
} else {
let shape = Shape::indented(offset, context.config).sub_width(1)?;
+ let lo = if let Some(generics) = struct_parts.generics {
+ generics.span.hi()
+ } else {
+ struct_parts.ident.span.hi()
+ };
result = overflow::rewrite_with_parens(
context,
&result,
fields.iter(),
shape,
- span,
+ mk_sp(lo, span.hi()),
context.config.fn_call_width(),
None,
)?;
Some(result)
}
-fn rewrite_type<R: Rewrite>(
+pub(crate) fn rewrite_type<R: Rewrite>(
context: &RewriteContext<'_>,
indent: Indent,
ident: symbol::Ident,
};
StaticParts {
prefix: "const",
- vis: &DEFAULT_VISIBILITY,
+ vis: &ti.vis,
ident: ti.ident,
ty,
mutability: ast::Mutability::Not,
Some(format!("{}{};", prefix, ty_str))
}
}
-
-pub(crate) fn rewrite_type_alias(
- ident: symbol::Ident,
- ty_opt: Option<&ptr::P<ast::Ty>>,
- generics: &ast::Generics,
- generic_bounds_opt: Option<&ast::GenericBounds>,
- context: &RewriteContext<'_>,
- indent: Indent,
- vis: &ast::Visibility,
- span: Span,
-) -> Option<String> {
- rewrite_type(
- context,
- indent,
- ident,
- vis,
- generics,
- generic_bounds_opt,
- ty_opt,
- span,
- )
-}
-
struct OpaqueType<'a> {
bounds: &'a ast::GenericBounds,
}
}
}
-pub(crate) fn rewrite_opaque_impl_type(
- context: &RewriteContext<'_>,
- ident: symbol::Ident,
- generics: &ast::Generics,
- generic_bounds: &ast::GenericBounds,
- indent: Indent,
-) -> Option<String> {
- let ident_str = rewrite_ident(context, ident);
- // 5 = "type "
- let generics_shape = Shape::indented(indent, context.config).offset_left(5)?;
- let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?;
- let prefix = format!("type {} =", generics_str);
- let rhs = OpaqueType {
- bounds: generic_bounds,
- };
-
- rewrite_assign_rhs(
- context,
- &prefix,
- &rhs,
- Shape::indented(indent, context.config).sub_width(1)?,
- )
- .map(|s| s + ";")
-}
-
-pub(crate) fn rewrite_associated_impl_type(
+pub(crate) fn rewrite_impl_type(
ident: symbol::Ident,
vis: &ast::Visibility,
defaultness: ast::Defaultness,
indent: Indent,
span: Span,
) -> Option<String> {
- let result = rewrite_type_alias(ident, ty_opt, generics, None, context, indent, vis, span)?;
+ // 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)),
let param_attrs_result = self
.attrs
.rewrite(context, Shape::legacy(shape.width, shape.indent))?;
- let (span, has_multiple_attr_lines) = if !self.attrs.is_empty() {
+ // N.B. Doc comments aren't typically valid syntax, but could appear
+ // in the presence of certain macros - https://github.com/rust-lang/rustfmt/issues/4936
+ let (span, has_multiple_attr_lines, has_doc_comments) = if !self.attrs.is_empty() {
let num_attrs = self.attrs.len();
(
mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()),
param_attrs_result.contains('\n'),
+ self.attrs.iter().any(|a| a.is_doc_comment()),
)
} else {
- (mk_sp(self.span.lo(), self.span.lo()), false)
+ (mk_sp(self.span.lo(), self.span.lo()), false, false)
};
if let Some(ref explicit_self) = self.to_self() {
has_multiple_attr_lines,
)
} else if is_named_param(self) {
+ let param_name = &self
+ .pat
+ .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
let mut result = combine_strs_with_missing_comments(
context,
¶m_attrs_result,
- &self
- .pat
- .rewrite(context, Shape::legacy(shape.width, shape.indent))?,
+ param_name,
span,
shape,
- !has_multiple_attr_lines,
+ !has_multiple_attr_lines && !has_doc_comments,
)?;
if !is_empty_infer(&*self.ty, self.pat.span) {
result.push_str(&after_comment);
let overhead = last_line_width(&result);
let max_width = shape.width.checked_sub(overhead)?;
- let ty_str = self
+ if let Some(ty_str) = self
.ty
- .rewrite(context, Shape::legacy(max_width, shape.indent))?;
- result.push_str(&ty_str);
+ .rewrite(context, Shape::legacy(max_width, shape.indent))
+ {
+ result.push_str(&ty_str);
+ } else {
+ result = combine_strs_with_missing_comments(
+ context,
+ &(param_attrs_result + &shape.to_string_with_newline(context.config)),
+ param_name,
+ span,
+ shape,
+ !has_multiple_attr_lines,
+ )?;
+ result.push_str(&before_comment);
+ result.push_str(colon_spaces(context.config));
+ result.push_str(&after_comment);
+ let overhead = last_line_width(&result);
+ let max_width = shape.width.checked_sub(overhead)?;
+ let ty_str = self
+ .ty
+ .rewrite(context, Shape::legacy(max_width, shape.indent))?;
+ result.push_str(&ty_str);
+ }
}
Some(result)
context,
shape.indent,
self.ident,
- &FnSig::from_method_sig(&fn_sig, generics, self.vis.clone()),
+ &FnSig::from_method_sig(&fn_sig, generics, &self.vis),
span,
FnBraceStyle::None,
)
ast::ForeignItemKind::TyAlias(ref ty_alias_kind) => {
let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
**ty_alias_kind;
- rewrite_type_alias(
- self.ident,
- type_default.as_ref(),
- generics,
- Some(generic_bounds),
+ rewrite_type(
&context,
shape.indent,
+ self.ident,
&self.vis,
+ generics,
+ Some(generic_bounds),
+ type_default.as_ref(),
self.span,
)
}
result.push_str(&comment);
if !inner_item.is_empty() {
- if tactic == DefinitiveListTactic::Vertical || tactic == DefinitiveListTactic::Mixed
- {
- // We cannot keep pre-comments on the same line if the comment if normalized.
+ use DefinitiveListTactic::*;
+ if matches!(tactic, Vertical | Mixed | SpecialMacro(_)) {
+ // We cannot keep pre-comments on the same line if the comment is normalized.
let keep_comment = if formatting.config.normalize_comments()
|| item.pre_comment_style == ListItemCommentStyle::DifferentLine
{
line_len = item.item.as_ref().map_or(0, |s| unicode_str_width(&s));
}
} else {
- result.push(' ');
+ result.push(' ')
}
}
item_max_width = None;
}
result.push_str(&nested_indent_str);
result.push_str(&body_str);
+ result.push_str(&comma);
return Some(result);
}
}
pub(crate) fn format_missing_with_indent(&mut self, end: BytePos) {
+ self.format_missing_indent(end, true)
+ }
+
+ pub(crate) fn format_missing_no_indent(&mut self, end: BytePos) {
+ self.format_missing_indent(end, false)
+ }
+
+ fn format_missing_indent(&mut self, end: BytePos, should_indent: bool) {
let config = self.config;
self.format_missing_inner(end, |this, last_snippet, snippet| {
this.push_str(last_snippet.trim_end());
// No new lines in the snippet.
this.push_str("\n");
}
- let indent = this.block_indent.to_string(config);
- this.push_str(&indent);
- })
- }
-
- pub(crate) fn format_missing_no_indent(&mut self, end: BytePos) {
- self.format_missing_inner(end, |this, last_snippet, _| {
- this.push_str(last_snippet.trim_end());
+ if should_indent {
+ let indent = this.block_indent.to_string(config);
+ this.push_str(&indent);
+ }
})
}
FieldDef(&'a ast::FieldDef),
TuplePatField(&'a TuplePatField<'a>),
Ty(&'a ast::Ty),
+ Pat(&'a ast::Pat),
}
impl<'a> Rewrite for OverflowableItem<'a> {
OverflowableItem::FieldDef(sf) => f(*sf),
OverflowableItem::TuplePatField(pat) => f(*pat),
OverflowableItem::Ty(ty) => f(*ty),
+ OverflowableItem::Pat(pat) => f(*pat),
}
}
}
}
-impl_into_overflowable_item_for_ast_node!(Expr, GenericParam, NestedMetaItem, FieldDef, Ty);
+impl_into_overflowable_item_for_ast_node!(Expr, GenericParam, NestedMetaItem, FieldDef, Ty, Pat);
impl_into_overflowable_item_for_rustfmt_types!([MacroArg], [SegmentParam, TuplePatField]);
pub(crate) fn into_overflowable_list<'a, T>(
use crate::comment::{combine_strs_with_missing_comments, FindUncommented};
use crate::config::lists::*;
+use crate::config::Version;
use crate::expr::{can_be_overflowed_expr, rewrite_unary_prefix, wrap_struct_field};
use crate::lists::{
definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape,
PatKind::Path(ref q_self, ref path) => {
rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)
}
- PatKind::TupleStruct(_, ref path, ref pat_vec) => {
- let path_str = rewrite_path(context, PathContext::Expr, None, path, shape)?;
+ PatKind::TupleStruct(ref q_self, ref path, ref pat_vec) => {
+ let path_str =
+ rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)?;
rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
}
PatKind::Lit(ref expr) => expr.rewrite(context, shape),
- PatKind::Slice(ref slice_pat) => {
+ PatKind::Slice(ref slice_pat) if context.config.version() == Version::One => {
let rw: Vec<String> = slice_pat
.iter()
.map(|p| {
.collect();
Some(format!("[{}]", rw.join(", ")))
}
- PatKind::Struct(_, ref path, ref fields, ellipsis) => {
- rewrite_struct_pat(path, fields, ellipsis, self.span, context, shape)
+ PatKind::Slice(ref slice_pat) => overflow::rewrite_with_square_brackets(
+ context,
+ "",
+ slice_pat.iter(),
+ shape,
+ self.span,
+ None,
+ None,
+ ),
+ PatKind::Struct(ref qself, ref path, ref fields, ellipsis) => {
+ rewrite_struct_pat(qself, path, fields, ellipsis, self.span, context, shape)
}
PatKind::MacCall(ref mac) => {
rewrite_macro(mac, None, context, shape, MacroPosition::Pat)
}
fn rewrite_struct_pat(
+ qself: &Option<ast::QSelf>,
path: &ast::Path,
fields: &[ast::PatField],
ellipsis: bool,
) -> Option<String> {
// 2 = ` {`
let path_shape = shape.sub_width(2)?;
- let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
+ let path_str = rewrite_path(context, PathContext::Expr, qself.as_ref(), path, path_shape)?;
if fields.is_empty() && !ellipsis {
return Some(format!("{} {{}}", path_str));
merge_use_trees(normalized_items, SharedPrefix::Module)
}
ImportGranularity::Item => flatten_use_trees(normalized_items),
+ ImportGranularity::One => merge_use_trees(normalized_items, SharedPrefix::One),
ImportGranularity::Preserve => normalized_items,
};
impl Spanned for ast::Param {
fn span(&self) -> Span {
if crate::items::is_named_param(self) {
- mk_sp(self.pat.span.lo(), self.ty.span.hi())
+ mk_sp(crate::items::span_lo_for_param(self), self.ty.span.hi())
} else {
self.ty.span
}
self.parse_sess.source_map().span_to_filename(span).into()
}
+ pub(crate) fn span_to_file_contents(&self, span: Span) -> Lrc<rustc_span::SourceFile> {
+ self.parse_sess
+ .source_map()
+ .lookup_source_file(span.data().lo)
+ }
+
pub(crate) fn span_to_first_line_string(&self, span: Span) -> String {
let file_lines = self.parse_sess.source_map().span_to_lines(span).ok();
#[test]
fn stdin_disable_all_formatting_test() {
init_log();
- match option_env!("CFG_RELEASE_CHANNEL") {
- None | Some("nightly") => {}
- // These tests require nightly.
- _ => return,
- }
let input = String::from("fn main() { println!(\"This should not be formatted.\"); }");
let mut child = Command::new(rustfmt().to_str().unwrap())
.stdin(Stdio::piped())
reader
.lines()
.map(|line| line.expect("failed getting line"))
- .take_while(|line| line_regex.is_match(line))
+ .filter(|line| line_regex.is_match(line))
.filter_map(|line| {
regex.captures_iter(&line).next().map(|capture| {
(
SegmentParam::Const(const_) => const_.rewrite(context, shape),
SegmentParam::LifeTime(lt) => lt.rewrite(context, shape),
SegmentParam::Type(ty) => ty.rewrite(context, shape),
- SegmentParam::Binding(assoc_ty_constraint) => {
- let mut result = match assoc_ty_constraint.kind {
- ast::AssocTyConstraintKind::Bound { .. } => {
- format!("{}: ", rewrite_ident(context, assoc_ty_constraint.ident))
- }
- ast::AssocTyConstraintKind::Equality { .. } => {
- match context.config.type_punctuation_density() {
- TypeDensity::Wide => {
- format!("{} = ", rewrite_ident(context, assoc_ty_constraint.ident))
- }
- TypeDensity::Compressed => {
- format!("{}=", rewrite_ident(context, assoc_ty_constraint.ident))
- }
- }
- }
- };
+ SegmentParam::Binding(atc) => atc.rewrite(context, shape),
+ }
+ }
+}
- let budget = shape.width.checked_sub(result.len())?;
- let rewrite = assoc_ty_constraint
- .kind
- .rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
- result.push_str(&rewrite);
- Some(result)
- }
+impl Rewrite for ast::AssocTyConstraint {
+ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
+ use ast::AssocTyConstraintKind::{Bound, Equality};
+
+ let mut result = String::with_capacity(128);
+ result.push_str(rewrite_ident(context, self.ident));
+
+ if let Some(ref gen_args) = self.gen_args {
+ let budget = shape.width.checked_sub(result.len())?;
+ let shape = Shape::legacy(budget, shape.indent + result.len());
+ let gen_str = rewrite_generic_args(gen_args, context, shape, gen_args.span())?;
+ result.push_str(&gen_str);
}
+
+ let infix = match (&self.kind, context.config.type_punctuation_density()) {
+ (Bound { .. }, _) => ": ",
+ (Equality { .. }, TypeDensity::Wide) => " = ",
+ (Equality { .. }, TypeDensity::Compressed) => "=",
+ };
+ result.push_str(infix);
+
+ let budget = shape.width.checked_sub(result.len())?;
+ let shape = Shape::legacy(budget, shape.indent + result.len());
+ let rewrite = self.kind.rewrite(context, shape)?;
+ result.push_str(&rewrite);
+
+ Some(result)
}
}
};
if let Some(ref args) = segment.args {
+ let generics_str = rewrite_generic_args(args, context, shape, mk_sp(*span_lo, span_hi))?;
match **args {
ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
- let param_list = data
- .args
- .iter()
- .map(|x| match x {
- ast::AngleBracketedArg::Arg(generic_arg) => {
- SegmentParam::from_generic_arg(generic_arg)
- }
- ast::AngleBracketedArg::Constraint(constraint) => {
- SegmentParam::Binding(constraint)
- }
- })
- .collect::<Vec<_>>();
-
// HACK: squeeze out the span between the identifier and the parameters.
// The hack is requried so that we don't remove the separator inside macro calls.
// This does not work in the presence of comment, hoping that people are
};
result.push_str(separator);
- let generics_str = overflow::rewrite_with_angle_brackets(
- context,
- "",
- param_list.iter(),
- shape,
- mk_sp(*span_lo, span_hi),
- )?;
-
// Update position of last bracket.
*span_lo = context
.snippet_provider
.span_after(mk_sp(*span_lo, span_hi), "<");
-
- result.push_str(&generics_str)
- }
- ast::GenericArgs::Parenthesized(ref data) => {
- result.push_str(&format_function_type(
- data.inputs.iter().map(|x| &**x),
- &data.output,
- false,
- data.span,
- context,
- shape,
- )?);
}
_ => (),
}
+ result.push_str(&generics_str)
}
Some(result)
}
}
+fn rewrite_generic_args(
+ gen_args: &ast::GenericArgs,
+ context: &RewriteContext<'_>,
+ shape: Shape,
+ span: Span,
+) -> Option<String> {
+ match gen_args {
+ ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
+ let args = data
+ .args
+ .iter()
+ .map(|x| match x {
+ ast::AngleBracketedArg::Arg(generic_arg) => {
+ SegmentParam::from_generic_arg(generic_arg)
+ }
+ ast::AngleBracketedArg::Constraint(constraint) => {
+ SegmentParam::Binding(constraint)
+ }
+ })
+ .collect::<Vec<_>>();
+
+ overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span)
+ }
+ ast::GenericArgs::Parenthesized(ref data) => format_function_type(
+ data.inputs.iter().map(|x| &**x),
+ &data.output,
+ false,
+ data.span,
+ context,
+ shape,
+ ),
+ _ => Some("".to_owned()),
+ }
+}
+
fn rewrite_bounded_lifetime(
lt: &ast::Lifetime,
bounds: &[ast::GenericBound],
if let ast::GenericParamKind::Const {
ref ty,
kw_span: _,
- default: _,
+ default,
} = &self.kind
{
result.push_str("const ");
result.push_str(rewrite_ident(context, self.ident));
result.push_str(": ");
result.push_str(&ty.rewrite(context, shape)?);
+ if let Some(default) = default {
+ let eq_str = match context.config.type_punctuation_density() {
+ TypeDensity::Compressed => "=",
+ TypeDensity::Wide => " = ",
+ };
+ result.push_str(eq_str);
+ let budget = shape.width.checked_sub(result.len())?;
+ let rewrite = default.rewrite(context, Shape::legacy(budget, shape.indent))?;
+ result.push_str(&rewrite);
+ }
} else {
result.push_str(rewrite_ident(context, self.ident));
}
use rustc_ast::{ast, token::DelimToken, visit, AstLike};
use rustc_data_structures::sync::Lrc;
-use rustc_span::{symbol, BytePos, Pos, Span, DUMMY_SP};
+use rustc_span::{symbol, BytePos, Pos, Span};
use crate::attr::*;
use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices};
use crate::config::{BraceStyle, Config};
use crate::coverage::transform_missing_snippet;
use crate::items::{
- format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item,
- rewrite_associated_impl_type, rewrite_extern_crate, rewrite_opaque_impl_type,
- rewrite_opaque_type, rewrite_type_alias, FnBraceStyle, FnSig, StaticParts, StructParts,
+ 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,
};
use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition};
use crate::modules::Module;
indent,
item.ident,
&fn_signature,
+ &item.vis,
generics,
item.span,
);
**alias_kind;
match ty {
Some(ty) => {
- let rewrite = rewrite_type_alias(
- item.ident,
- Some(&*ty),
- generics,
- Some(generic_bounds),
+ 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);
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 vis = ast::Visibility {
- kind: ast::VisibilityKind::Inherited,
- span: DUMMY_SP,
- tokens: None,
- };
let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Trait);
self.visit_fn(
- visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &vis, Some(body)),
+ visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &ti.vis, Some(body)),
generics,
&sig.decl,
ti.span,
} else {
let indent = self.block_indent;
let rewrite =
- self.rewrite_required_fn(indent, ti.ident, sig, generics, ti.span);
+ self.rewrite_required_fn(indent, ti.ident, sig, &ti.vis, generics, ti.span);
self.push_rewrite(ti.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_alias(
- ti.ident,
- type_default.as_ref(),
- generics,
- Some(generic_bounds),
+ 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);
} else {
let indent = self.block_indent;
let rewrite =
- self.rewrite_required_fn(indent, ii.ident, sig, generics, ii.span);
+ 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;
- let rewrite_associated = || {
- rewrite_associated_impl_type(
+ self.push_rewrite(
+ ii.span,
+ rewrite_impl_type(
ii.ident,
&ii.vis,
defaultness,
&self.get_context(),
self.block_indent,
ii.span,
- )
- };
- let rewrite = match ty {
- None => rewrite_associated(),
- Some(ty) => match ty.kind {
- ast::TyKind::ImplTrait(_, ref bounds) => rewrite_opaque_impl_type(
- &self.get_context(),
- ii.ident,
- generics,
- bounds,
- self.block_indent,
- ),
- _ => rewrite_associated(),
- },
- };
- self.push_rewrite(ii.span, rewrite);
+ ),
+ );
}
ast::AssocItemKind::MacCall(ref mac) => {
self.visit_mac(mac, Some(ii.ident), MacroPosition::Item);
--- /dev/null
+[package]
+name = "cargo-fmt-test"
+version = "0.1.0"
+authors = ["calebcartwright"]
+edition = "2018"
+
+[dependencies]
+indexmap = "1.0.2"
+
+[workspace]
+members = [
+ "dependency-dir-name",
+]
\ No newline at end of file
--- /dev/null
+[package]
+name = "dependency-crate-name"
+version = "0.1.0"
+authors = ["calebcartwright"]
+edition = "2018"
+
+[dependencies]
+subdep-crate-name = { path = "subdep-dir-name" }
+indexmap = "1.0.2"
+rusty-hook = "0.8.4"
\ No newline at end of file
--- /dev/null
+#[cfg(test)]
+mod tests {
+#[test]
+fn it_works() {
+ assert_eq!(2 + 2, 4);
+}
+}
--- /dev/null
+[package]
+name = "subdep-crate-name"
+version = "0.1.0"
+authors = ["calebcartwright"]
+edition = "2018"
+
+[dependencies]
--- /dev/null
+#[cfg(test)]
+mod tests {
+#[test]
+fn sub_test_that_works() {
+ assert_eq!(3 + 3, 6);
+}
+ }
--- /dev/null
+fn main() {
+println!("Hello, world!");
+}
--- /dev/null
+[package]
+name = "e"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+c = { path = "../ws/c" }
+
+[workspace]
--- /dev/null
+struct E{ }
--- /dev/null
+[workspace]
+members = [
+ "a",
+ "b"
+]
\ No newline at end of file
--- /dev/null
+[package]
+name = "a"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+d = { path = "./d" }
--- /dev/null
+[package]
+name = "d"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+e = { path = "../../../e" }
+f = { path = "f" }
--- /dev/null
+[package]
+name = "f"
+version = "0.1.0"
+edition = "2018"
--- /dev/null
+struct F{ }
\ No newline at end of file
--- /dev/null
+struct D{ }
\ No newline at end of file
--- /dev/null
+struct D{ }
\ No newline at end of file
--- /dev/null
+[package]
+name = "b"
+version = "0.1.0"
+edition = "2018"
+[dependencies]
+c = { path = "../c" }
--- /dev/null
+struct B{ }
\ No newline at end of file
--- /dev/null
+[package]
+name = "c"
+version = "0.1.0"
+edition = "2018"
--- /dev/null
+struct C{ }
\ No newline at end of file
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ^ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ & abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ | abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ << abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >> abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ < abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <= abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ > abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >= abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ == abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ && abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ || abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {
+ //
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ * abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ - abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ / abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ * abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ * abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ / abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ / abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ + abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ match val {
+ ThisIsA::ReallyLongPatternNameToHelpOverflowTheNextValueOntoTheNextLine | ThisIsA::SecondValueSeparatedByAPipe | ThisIsA::ThirdValueSeparatedByAPipe => {
+ //
+ }
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
--- /dev/null
+// @generated
+// rustfmt-format_generated_files: false
+
+fn main()
+{
+ println!("hello, world")
+ ;
+}
--- /dev/null
+// @generated
+// rustfmt-format_generated_files: true
+
+fn main()
+{
+ println!("hello, world")
+ ;
+}
--- /dev/null
+// rustfmt-hex_literal_case: Lower
+fn main() {
+ let h1 = 0xCAFE_5EA7;
+ let h2 = 0xCAFE_F00Du32;
+}
--- /dev/null
+// rustfmt-hex_literal_case: Upper
+fn main() {
+ let h1 = 0xCaFE_5ea7;
+ let h2 = 0xCAFE_F00Du32;
+}
// Comment 3
}
+#[inherent]
+impl Visible for Bar {
+ pub const C: i32;
+ pub type T;
+ pub fn f();
+ pub fn g() {}
+}
+
pub unsafe impl<'a, 'b, X, Y: Foo<Bar>> !Foo<'a, X> for Bar<'b, Y> where X: Foo<'a, Z> {
fn foo() { "hi" }
}
--- /dev/null
+// rustfmt-imports_granularity: One
+
+use b;
+use a::ac::{aca, acb};
+use a::{aa::*, ab};
+
+use a as x;
+use b::ba;
+use a::{aa, ab};
+
+use a::aa::aaa;
+use a::ab::aba as x;
+use a::aa::*;
+
+use a::aa;
+use a::ad::ada;
+#[cfg(test)]
+use a::{ab, ac::aca};
+use b;
+#[cfg(test)]
+use b::{
+ ba, bb,
+ bc::bca::{bcaa, bcab},
+};
+
+pub use a::aa;
+pub use a::ae;
+use a::{ab, ac, ad};
+use b::ba;
+pub use b::{bb, bc::bca};
+
+use a::aa::aaa;
+use a::ac::{aca, acb};
+use a::{aa::*, ab};
+use b::{
+ ba,
+ bb::{self, bba},
+};
+
+use crate::a;
+use crate::b::ba;
+use c::ca;
+
+use super::a;
+use c::ca;
+use super::b::ba;
+
+use crate::a;
+use super::b;
+use c::{self, ca};
+
+use a::{
+ // some comment
+ aa::{aaa, aab},
+ ab,
+ // another comment
+ ac::aca,
+};
+use b as x;
+use a::ad::ada;
--- /dev/null
+// rustfmt-format_code_in_doc_comments: true
+
+/// Should format
+/// ```rust
+/// assert!( false );
+/// ```
+///
+/// Should format
+/// ```rust,should_panic
+/// assert!( false );
+/// ```
+///
+/// Should format
+/// ```rust,should_panic,edition2018
+/// assert!( false );
+/// ```
+///
+/// Should format
+/// ```rust , should_panic , edition2018
+/// assert!( false );
+/// ```
+///
+/// Should not format
+/// ```ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (not all are rust)
+/// ```rust,ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```compile_fail
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```rust,compile_fail
+/// assert!( false );
+/// ```
+///
+/// Various unspecified ones that should format
+/// ```
+/// assert!( false );
+/// ```
+///
+/// ```,
+/// assert!( false );
+/// ```
+///
+/// ```,,,,,
+/// assert!( false );
+/// ```
+///
+/// ```,,, rust ,,
+/// assert!( false );
+/// ```
+///
+/// Should not format
+/// ```,,, rust , ignore,
+/// assert!( false );
+/// ```
+///
+/// Few empty ones
+/// ```
+/// ```
+///
+/// ```rust
+/// ```
+///
+/// ```ignore
+/// ```
+fn foo() {}
--- /dev/null
+// rustfmt-version: Two
+fn main() {
+ let [aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccc, ddddddddddddddddddddddddd] = panic!();
+}
--- /dev/null
+info!(//debug
+ "{}: sending function_code={:04x} data={:04x} crc=0x{:04X} data={:02X?}",
+ self.name, function_code, data, crc, output_cmd
+);
--- /dev/null
+#![feature(const_generics_defaults)]
+struct Foo<const N: usize = 1, const N2: usize = 2>;
+struct Bar<const N: usize, const N2: usize = { N +
+1 }>;
+struct Lots<const N1BlahFooUwU: usize = { 10 + 28 + 1872 / 10 * 3 },const N2SecondParamOhmyyy: usize = { N1BlahFooUwU / 2 + 10 * 2 },>;
+struct NamesRHard<const N: usize = { 1 + 1 + 1 + 1 + 1 + 1 }>;
+struct FooBar<
+ const LessThan100ButClose: usize = {1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1}
+>;
+struct FooBarrrrrrrr<const N: usize = {13478234326456456444323871+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+ 1+1+1+1 + 1},>;
--- /dev/null
+
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X { a: 1_000, b: 1_000, .. }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
\ No newline at end of file
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ really_really_long_field_a: i32,
+ really_really_really_long_field_b: i32,
+ really_really_really_really_long_field_c: i32,
+ really_really_really_really_really_long_field_d: i32,
+ really_really_really_really_really_really_long_field_e: i32,
+ f: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X {
+ really_really_long_field_a: 10,
+ really_really_really_long_field_b: 10,
+ really_really_really_really_long_field_c: 10,
+ really_really_really_really_really_long_field_d: 10,
+ really_really_really_really_really_really_long_field_e: 10, ..
+ }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32,
+ e: i32,
+ f: i32,
+ g: i32,
+ h: i32,
+ i: i32,
+ j: i32,
+ k: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X {
+ a: 1_000, b: 1_000, c: 1_000, d: 1_000, e: 1_000, f: 1_000, g: 1_000, h: 1_000, i: 1_000, j: 1_000, ..
+ }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+// rustfmt-enum_discrim_align_threshold: 30
+// rustfmt-imports_layout: HorizontalVertical
+
+#[derive(Default)]
+struct InnerStructA { bbbbbbbbb: i32, cccccccc: i32 }
+
+enum SomeEnumNamedD {
+ E(InnerStructA),
+ F {
+ ggggggggggggggggggggggggg: bool,
+ h: bool,
+ }
+}
+
+impl SomeEnumNamedD {
+ fn f_variant() -> Self {
+ Self::F { ggggggggggggggggggggggggg: true, h: true }
+ }
+}
+
+fn main() {
+ let kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk = SomeEnumNamedD::f_variant();
+ let something_we_care_about = matches!(
+ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk,
+ SomeEnumNamedD::F {
+ ggggggggggggggggggggggggg: true,
+ ..
+ }
+ );
+
+ if something_we_care_about {
+ println!("Yup it happened");
+ }
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X { a: i32, b: i32 }
+
+fn test(x: X) {
+ let y = matches!(x, X {
+ a: 1,
+ ..
+ });
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ really_really_long_field_a: i32,
+ really_really_really_long_field_b: i32,
+ really_really_really_really_long_field_c: i32,
+ really_really_really_really_really_long_field_d: i32,
+ really_really_really_really_really_really_long_field_e: i32,
+ f: i32,
+}
+
+fn test(x: X) {
+ let y = matches!(x, X {
+ really_really_long_field_a: 10,
+ really_really_really_long_field_b: 10,
+ really_really_really_really_long_field_c: 10,
+ really_really_really_really_really_long_field_d: 10,
+ really_really_really_really_really_really_long_field_e: 10,
+ ..
+ });
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32,
+ e: i32,
+ f: i32,
+ g: i32,
+ h: i32,
+ i: i32,
+ j: i32,
+ k: i32,
+}
+
+fn test(x: X) {
+ let y = matches!(x, X {
+ a: 1_000, b: 1_000, c: 1_000, d: 1_000, e: 1_000, f: 1_000, g: 1_000, h: 1_000, i: 1_000, j: 1_000, ..
+ });
+}
\ No newline at end of file
--- /dev/null
+#[derive(/*Debug, */Clone)]
+struct Foo;
--- /dev/null
+#[derive(
+/* ---------- Some really important comment that just had to go inside the derive --------- */
+Debug, Clone, Eq, PartialEq,
+)]
+struct Foo {
+ a: i32,
+ b: T,
+}
+
+#[derive(
+/*
+ Some really important comment that just had to go inside the derive.
+ Also had to be put over multiple lines
+*/
+Debug, Clone, Eq, PartialEq,
+)]
+struct Bar {
+ a: i32,
+ b: T,
+}
--- /dev/null
+#[derive(
+/* ---------- Some really important comment that just had to go inside the derive --------- */
+Debug, Clone,/* Another comment */Eq, PartialEq,
+)]
+struct Foo {
+ a: i32,
+ b: T,
+}
--- /dev/null
+pub(crate) struct ASlash(
+ // hello
+ i32
+);
+
+pub(crate) struct AStar(
+ /* hello */
+ i32
+);
+
+pub(crate) struct BStar(/* hello */ i32);
+
--- /dev/null
+fn a1(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] a: u8) {}
+fn b1(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] bb: u8) {}
+fn a2(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] a: u8) {}
+fn b2(#[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] bb: u8) {}
--- /dev/null
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+trait Trait<T> {
+ type Type<'a> where T: 'a;
+ fn foo(x: &T) -> Self::Type<'_>;
+}
+impl<T> Trait<T> for () {
+ type Type<'a> where T: 'a = &'a T;
+ fn foo(x: &T) -> Self::Type<'_> {
+ x
+ }
+}
--- /dev/null
+trait Bar {
+ type X<'a> where Self: 'a;
+}
--- /dev/null
+// rustfmt-hard_tabs: true
+
+#[macro_export]
+macro_rules! main {
+ () => {
+ #[spirv(fragment)]
+ pub fn main_fs(
+ mut out_color: ::spirv_std::storage_class::Output<Vec4>,
+ #[spirv(descriptor_set = 1)]iChannelResolution: ::spirv_std::storage_class::UniformConstant<
+ [::spirv_std::glam::Vec3A; 4],
+ >,
+ ) {
+ }
+ };
+}
--- /dev/null
+#![feature(generic_associated_types)]
+#![feature(min_type_alias_impl_trait)]
+
+impl SomeTrait for SomeType {
+ type SomeGAT<'a> where Self: 'a = impl SomeOtherTrait;
+}
\ No newline at end of file
--- /dev/null
+#![feature(generic_associated_types)]
+
+impl SomeStruct {
+ fn process<T>(v: T) -> <Self as GAT>::R<T>
+ where Self: GAT<R<T> = T>
+ {
+ SomeStruct::do_something(v)
+ }
+}
--- /dev/null
+trait Foo {
+ type Arg<'a>;
+}
+
+struct Bar<T>(T) where for<'a> T: Foo<Arg<'a> = ()>;
--- /dev/null
+mod test {
+ extern "C" {fn test();}
+}
+
+extern "C" {fn test();}
\ No newline at end of file
"line1";
"line2"
}
+ ThisIsA::Guard if true => {
+ "line1";
+ "line2"
+ }
+ ThisIsA::ReallyLongPattern(ThatWillForce::TheGuard, ToWrapOnto::TheFollowingLine) if true => {
+ "line1";
+ "line2"
+ }
b => (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb),
}
+ DDDDDDDD
+ DDDDDDDDD
+ EEEEEEE;
+
+trait Visible {
+ pub const C: i32;
+ pub type T;
+ pub fn f();
+ pub fn g() {}
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ^
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ &
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ |
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <<
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >>
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ <=
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ >=
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ==
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ if abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ &&
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ||
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ {
+ //
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ *
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ -
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ /
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ *
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ *
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ /
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ /
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ match val {
+ ThisIsA::ReallyLongPatternNameToHelpOverflowTheNextValueOntoTheNextLine |
+ ThisIsA::SecondValueSeparatedByAPipe |
+ ThisIsA::ThirdValueSeparatedByAPipe => {
+ //
+ }
+ }
+}
--- /dev/null
+// rustfmt-binop_separator: Back
+
+fn main() {
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+
+ let value = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ..=
+ abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;
+}
--- /dev/null
+// @generated
+// rustfmt-format_generated_files: false
+
+fn main()
+{
+ println!("hello, world")
+ ;
+}
--- /dev/null
+// @generated
+// rustfmt-format_generated_files: true
+
+fn main() {
+ println!("hello, world");
+}
--- /dev/null
+// rustfmt-hex_literal_case: Lower
+fn main() {
+ let h1 = 0xcafe_5ea7;
+ let h2 = 0xcafe_f00du32;
+}
--- /dev/null
+// rustfmt-hex_literal_case: Preserve
+fn main() {
+ let h1 = 0xcAfE_5Ea7;
+ let h2 = 0xCaFe_F00du32;
+}
--- /dev/null
+// rustfmt-hex_literal_case: Upper
+fn main() {
+ let h1 = 0xCAFE_5EA7;
+ let h2 = 0xCAFE_F00Du32;
+}
// Comment 3
}
+#[inherent]
+impl Visible for Bar {
+ pub const C: i32;
+ pub type T;
+ pub fn f();
+ pub fn g() {}
+}
+
pub unsafe impl<'a, 'b, X, Y: Foo<Bar>> !Foo<'a, X> for Bar<'b, Y>
where
X: Foo<'a, Z>,
--- /dev/null
+// rustfmt-imports_granularity: One
+
+use {
+ a::{
+ aa::*,
+ ab,
+ ac::{aca, acb},
+ },
+ b,
+};
+
+use {
+ a::{self as x, aa, ab},
+ b::ba,
+};
+
+use a::{
+ aa::{aaa, *},
+ ab::aba as x,
+};
+
+#[cfg(test)]
+use a::{ab, ac::aca};
+#[cfg(test)]
+use b::{
+ ba, bb,
+ bc::bca::{bcaa, bcab},
+};
+use {
+ a::{aa, ad::ada},
+ b,
+};
+
+pub use {
+ a::{aa, ae},
+ b::{bb, bc::bca},
+};
+use {
+ a::{ab, ac, ad},
+ b::ba,
+};
+
+use {
+ a::{
+ aa::{aaa, *},
+ ab,
+ ac::{aca, acb},
+ },
+ b::{
+ ba,
+ bb::{self, bba},
+ },
+};
+
+use {
+ crate::{a, b::ba},
+ c::ca,
+};
+
+use {
+ super::{a, b::ba},
+ c::ca,
+};
+
+use {
+ super::b,
+ crate::a,
+ c::{self, ca},
+};
+
+use {
+ a::{
+ aa::{aaa, aab},
+ ab,
+ ac::aca,
+ ad::ada,
+ },
+ b as x,
+};
--- /dev/null
+// rustfmt-format_code_in_doc_comments: true
+
+/// Should format
+/// ```rust
+/// assert!(false);
+/// ```
+///
+/// Should format
+/// ```rust,should_panic
+/// assert!(false);
+/// ```
+///
+/// Should format
+/// ```rust,should_panic,edition2018
+/// assert!(false);
+/// ```
+///
+/// Should format
+/// ```rust , should_panic , edition2018
+/// assert!(false);
+/// ```
+///
+/// Should not format
+/// ```ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (not all are rust)
+/// ```rust,ignore
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```compile_fail
+/// assert!( false );
+/// ```
+///
+/// Should not format (rust compile_fail)
+/// ```rust,compile_fail
+/// assert!( false );
+/// ```
+///
+/// Various unspecified ones that should format
+/// ```
+/// assert!(false);
+/// ```
+///
+/// ```,
+/// assert!(false);
+/// ```
+///
+/// ```,,,,,
+/// assert!(false);
+/// ```
+///
+/// ```,,, rust ,,
+/// assert!(false);
+/// ```
+///
+/// Should not format
+/// ```,,, rust , ignore,
+/// assert!( false );
+/// ```
+///
+/// Few empty ones
+/// ```
+/// ```
+///
+/// ```rust
+/// ```
+///
+/// ```ignore
+/// ```
+fn foo() {}
--- /dev/null
+// rustfmt-version: Two
+fn main() {
+ let [
+ aaaaaaaaaaaaaaaaaaaaaaaaaa,
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
+ cccccccccccccccccccccccccc,
+ ddddddddddddddddddddddddd,
+ ] = panic!();
+}
--- /dev/null
+info!(
+ //debug
+ "{}: sending function_code={:04x} data={:04x} crc=0x{:04X} data={:02X?}",
+ self.name, function_code, data, crc, output_cmd
+);
--- /dev/null
+#![feature(const_generics_defaults)]
+struct Foo<const N: usize = 1, const N2: usize = 2>;
+struct Bar<const N: usize, const N2: usize = { N + 1 }>;
+struct Lots<
+ const N1BlahFooUwU: usize = { 10 + 28 + 1872 / 10 * 3 },
+ const N2SecondParamOhmyyy: usize = { N1BlahFooUwU / 2 + 10 * 2 },
+>;
+struct NamesRHard<const N: usize = { 1 + 1 + 1 + 1 + 1 + 1 }>;
+struct FooBar<
+ const LessThan100ButClose: usize = {
+ 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
+ },
+>;
+struct FooBarrrrrrrr<
+ const N: usize = {
+ 13478234326456456444323871
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ + 1
+ },
+>;
--- /dev/null
+#![feature(more_qualified_paths)]
+
+fn main() {
+ // destructure through a qualified path
+ let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
+}
+
+struct StructStruct {
+ br: i8,
+}
+
+struct Foo;
+
+trait A {
+ type Assoc;
+}
+
+impl A for Foo {
+ type Assoc = StructStruct;
+}
--- /dev/null
+#![feature(more_qualified_paths)]
+
+mod foo_bar {
+ pub enum Example {
+ Example1 {},
+ Example2 {},
+ }
+}
+
+fn main() {
+ foo!(crate::foo_bar::Example, Example1);
+
+ let i1 = foo_bar::Example::Example1 {};
+
+ assert_eq!(i1.foo_example(), 1);
+
+ let i2 = foo_bar::Example::Example2 {};
+
+ assert_eq!(i2.foo_example(), 2);
+}
+
+#[macro_export]
+macro_rules! foo {
+ ($struct:path, $variant:ident) => {
+ impl $struct {
+ pub fn foo_example(&self) -> i32 {
+ match self {
+ <$struct>::$variant { .. } => 1,
+ _ => 2,
+ }
+ }
+ }
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X {
+ a: 1_000,
+ b: 1_000,
+ ..
+ }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ really_really_long_field_a: i32,
+ really_really_really_long_field_b: i32,
+ really_really_really_really_long_field_c: i32,
+ really_really_really_really_really_long_field_d: i32,
+ really_really_really_really_really_really_long_field_e: i32,
+ f: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X {
+ really_really_long_field_a: 10,
+ really_really_really_long_field_b: 10,
+ really_really_really_really_long_field_c: 10,
+ really_really_really_really_really_long_field_d: 10,
+ really_really_really_really_really_really_long_field_e: 10,
+ ..
+ }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32,
+ e: i32,
+ f: i32,
+ g: i32,
+ h: i32,
+ i: i32,
+ j: i32,
+ k: i32,
+}
+
+fn test(x: X) {
+ let d = {
+ let e = {
+ let f = {
+ let g = {
+ let h = {
+ let i = {
+ let j = {
+ matches!(
+ x,
+ X {
+ a: 1_000,
+ b: 1_000,
+ c: 1_000,
+ d: 1_000,
+ e: 1_000,
+ f: 1_000,
+ g: 1_000,
+ h: 1_000,
+ i: 1_000,
+ j: 1_000,
+ ..
+ }
+ )
+ };
+ j
+ };
+ i
+ };
+ h
+ };
+ g
+ };
+ f
+ };
+ e
+ };
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+// rustfmt-enum_discrim_align_threshold: 30
+// rustfmt-imports_layout: HorizontalVertical
+
+#[derive(Default)]
+struct InnerStructA {
+ bbbbbbbbb: i32,
+ cccccccc: i32,
+}
+
+enum SomeEnumNamedD {
+ E(InnerStructA),
+ F {
+ ggggggggggggggggggggggggg: bool,
+ h: bool,
+ },
+}
+
+impl SomeEnumNamedD {
+ fn f_variant() -> Self {
+ Self::F {
+ ggggggggggggggggggggggggg: true,
+ h: true,
+ }
+ }
+}
+
+fn main() {
+ let kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk = SomeEnumNamedD::f_variant();
+ let something_we_care_about = matches!(
+ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk,
+ SomeEnumNamedD::F {
+ ggggggggggggggggggggggggg: true,
+ ..
+ }
+ );
+
+ if something_we_care_about {
+ println!("Yup it happened");
+ }
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+}
+
+fn test(x: X) {
+ let y = matches!(x, X { a: 1, .. });
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ really_really_long_field_a: i32,
+ really_really_really_long_field_b: i32,
+ really_really_really_really_long_field_c: i32,
+ really_really_really_really_really_long_field_d: i32,
+ really_really_really_really_really_really_long_field_e: i32,
+ f: i32,
+}
+
+fn test(x: X) {
+ let y = matches!(
+ x,
+ X {
+ really_really_long_field_a: 10,
+ really_really_really_long_field_b: 10,
+ really_really_really_really_long_field_c: 10,
+ really_really_really_really_really_long_field_d: 10,
+ really_really_really_really_really_really_long_field_e: 10,
+ ..
+ }
+ );
+}
--- /dev/null
+// rustfmt-struct_field_align_threshold: 30
+
+struct X {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32,
+ e: i32,
+ f: i32,
+ g: i32,
+ h: i32,
+ i: i32,
+ j: i32,
+ k: i32,
+}
+
+fn test(x: X) {
+ let y = matches!(
+ x,
+ X {
+ a: 1_000,
+ b: 1_000,
+ c: 1_000,
+ d: 1_000,
+ e: 1_000,
+ f: 1_000,
+ g: 1_000,
+ h: 1_000,
+ i: 1_000,
+ j: 1_000,
+ ..
+ }
+ );
+}
--- /dev/null
+#[derive(/*Debug, */ Clone)]
+struct Foo;
--- /dev/null
+#[derive(
+ /* ---------- Some really important comment that just had to go inside the derive --------- */
+ Debug,
+ Clone,
+ Eq,
+ PartialEq,
+)]
+struct Foo {
+ a: i32,
+ b: T,
+}
+
+#[derive(
+ /*
+ Some really important comment that just had to go inside the derive.
+ Also had to be put over multiple lines
+ */
+ Debug,
+ Clone,
+ Eq,
+ PartialEq,
+)]
+struct Bar {
+ a: i32,
+ b: T,
+}
--- /dev/null
+#[derive(
+ /* ---------- Some really important comment that just had to go inside the derive --------- */
+ Debug,
+ Clone,
+ /* Another comment */ Eq,
+ PartialEq,
+)]
+struct Foo {
+ a: i32,
+ b: T,
+}
--- /dev/null
+#[derive(Clone, Debug, Eq, PartialEq)]
+struct Foo;
+
+#[derive(Clone)]
+struct Bar;
--- /dev/null
+#![feature(more_qualified_paths)]
+macro_rules! show {
+ ($ty:ty, $ex:expr) => {
+ match $ex {
+ <$ty>::A(_val) => println!("got a"), // formatting should not remove <$ty>::
+ <$ty>::B => println!("got b"),
+ }
+ };
+}
--- /dev/null
+fn main() {
+ // the "in" inside the pattern produced invalid syntax
+ for variable_in_here /* ... */ in 0..1 {}
+}
--- /dev/null
+fn main() {
+ for in_in_in_in_in_in_in_in /* ... */ in 0..1 {}
+}
--- /dev/null
+fn main() {
+ for variable_in_x /* ... */ in 0..1 {
+ for variable_in_y /* ... */ in 0..1 {}
+ }
+}
--- /dev/null
+fn main() {
+ for variable_in_x /* ... */ in 0..1 {
+ for variable_in_y /* ... */ in 0..1 {
+ if false {
+
+ } else if false {
+
+ } else {
+
+ }
+ }
+ }
+}
--- /dev/null
+fn main() {
+ let in_ = false;
+
+ for variable_in_x /* ... */ in 0..1 {
+ for variable_in_y /* ... */ in 0..1 {
+ if in_ {
+
+ } else if in_ {
+
+ } else {
+
+ }
+ }
+ }
+}
--- /dev/null
+fn main() {
+ for variable_in_a /* ... */ in 0..1 {
+ for variable_in_b /* ... */ in 0..1 {
+ for variable_in_c /* ... */ in 0..1 {
+ for variable_in_d /* ... */ in 0..1 {
+ for variable_in_e /* ... */ in 0..1 {
+ for variable_in_f /* ... */ in 0..1 {
+ for variable_in_g /* ... */ in 0..1 {
+ for variable_in_h /* ... */ in 0..1 {
+ for variable_in_i /* ... */ in 0..1 {
+ for variable_in_j /* ... */ in 0..1 {
+ for variable_in_k /* ... */ in 0..1 {
+ for variable_in_l /* ... */ in 0..1 {
+ for variable_in_m /* ... */ in 0..1 {
+ for variable_in_n /* ... */ in 0..1 {
+ for variable_in_o /* ... */ in 0..1 {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+pub(crate) struct ASlash(
+ // hello
+ i32,
+);
+
+pub(crate) struct AStar(/* hello */ i32);
+
+pub(crate) struct BStar(/* hello */ i32);
--- /dev/null
+fn foo() {
+ with_woff2_glyf_table("tests/fonts/woff2/SFNT-TTF-Composite.woff2", |glyf| {
+ let actual = glyf
+ .records
+ .iter()
+ .map(|glyph| match glyph {
+ GlyfRecord::Parsed(
+ found @ Glyph {
+ data: GlyphData::Composite { .. },
+ ..
+ },
+ ) => Some(found),
+ _ => None,
+ })
+ .find(|candidate| candidate.is_some())
+ .unwrap()
+ .unwrap();
+
+ assert_eq!(*actual, expected)
+ });
+}
--- /dev/null
+fn a1(
+ #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
+ a: u8,
+) {
+}
+fn b1(
+ #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]
+ bb: u8,
+) {
+}
+fn a2(
+ #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] a: u8,
+) {
+}
+fn b2(
+ #[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] bb: u8,
+) {
+}
--- /dev/null
+fn bindings() {
+ let err = match (place_desc, explanation) {
+ (
+ Some(ref name),
+ BorrowExplanation::MustBeValidFor {
+ category:
+ category @ (ConstraintCategory::Return
+ | ConstraintCategory::CallArgument
+ | ConstraintCategory::OpaqueType),
+ from_closure: false,
+ ref region_name,
+ span,
+ ..
+ },
+ ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
+ .report_escaping_closure_capture(
+ borrow_spans,
+ borrow_span,
+ region_name,
+ category,
+ span,
+ &format!("`{}`", name),
+ ),
+ (
+ ref name,
+ BorrowExplanation::MustBeValidFor {
+ category: ConstraintCategory::Assignment,
+ from_closure: false,
+ region_name:
+ RegionName {
+ source: RegionNameSource::AnonRegionFromUpvar(upvar_span, ref upvar_name),
+ ..
+ },
+ span,
+ ..
+ },
+ ) => self.report_escaping_data(borrow_span, name, upvar_span, upvar_name, span),
+ (Some(name), explanation) => self.report_local_value_does_not_live_long_enough(
+ location,
+ &name,
+ &borrow,
+ drop_span,
+ borrow_spans,
+ explanation,
+ ),
+ (None, explanation) => self.report_temporary_value_does_not_live_long_enough(
+ location,
+ &borrow,
+ drop_span,
+ borrow_spans,
+ proper_span,
+ explanation,
+ ),
+ };
+}
--- /dev/null
+#![feature(generic_associated_types)]
+#![allow(incomplete_features)]
+
+trait Trait<T> {
+ type Type<'a>
+ where
+ T: 'a;
+ fn foo(x: &T) -> Self::Type<'_>;
+}
+impl<T> Trait<T> for () {
+ type Type<'a>
+ where
+ T: 'a,
+ = &'a T;
+ fn foo(x: &T) -> Self::Type<'_> {
+ x
+ }
+}
--- /dev/null
+trait Bar {
+ type X<'a>
+ where
+ Self: 'a;
+}
--- /dev/null
+// rustfmt-hard_tabs: true
+
+#[macro_export]
+macro_rules! main {
+ () => {
+ #[spirv(fragment)]
+ pub fn main_fs(
+ mut out_color: ::spirv_std::storage_class::Output<Vec4>,
+ #[spirv(descriptor_set = 1)]
+ iChannelResolution: ::spirv_std::storage_class::UniformConstant<
+ [::spirv_std::glam::Vec3A; 4],
+ >,
+ ) {
+ }
+ };
+}
--- /dev/null
+#![feature(generic_associated_types)]
+#![feature(min_type_alias_impl_trait)]
+
+impl SomeTrait for SomeType {
+ type SomeGAT<'a>
+ where
+ Self: 'a,
+ = impl SomeOtherTrait;
+}
--- /dev/null
+#[discard_params_doc]
+trait Trait {
+ fn foo(
+ &self,
+ /// some docs
+ bar: String,
+ /// another docs
+ baz: i32,
+ );
+}
--- /dev/null
+#![feature(generic_associated_types)]
+
+impl SomeStruct {
+ fn process<T>(v: T) -> <Self as GAT>::R<T>
+ where
+ Self: GAT<R<T> = T>,
+ {
+ SomeStruct::do_something(v)
+ }
+}
--- /dev/null
+trait Foo {
+ type Arg<'a>;
+}
+
+struct Bar<T>(T)
+where
+ for<'a> T: Foo<Arg<'a> = ()>;
--- /dev/null
+mod test {
+ extern "C" {
+ fn test();
+ }
+}
+
+extern "C" {
+ fn test();
+}
"line1";
"line2"
},
+ ThisIsA::Guard if true => {
+ "line1";
+ "line2"
+ },
+ ThisIsA::ReallyLongPattern(ThatWillForce::TheGuard, ToWrapOnto::TheFollowingLine)
+ if true =>
+ {
+ "line1";
+ "line2"
+ },
b => (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
+ DDDDDDDD
+ DDDDDDDDD
+ EEEEEEE;
+
+trait Visible {
+ pub const C: i32;
+ pub type T;
+ pub fn f();
+ pub fn g() {}
+}
&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!(
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 1330;
+const ROOT_ENTRY_LIMIT: usize = 1331;
const ISSUES_ENTRY_LIMIT: usize = 2488;
fn check_entries(path: &Path, bad: &mut bool) {
"requires-nightly",
"regression-*",
"perf-*",
- # I-* without I-nominated
- "I-*", "!I-nominated",
+ # I-* without I-*nominated
+ "I-*", "!I-*nominated",
"AsyncAwait-OnDeck",
]